[Go] #3.1 연산자 종류

[Go] #3.1 연산자 종류

강의 링크 : 한 눈에 끝내는 고랭 기초 #3 연산자 - 연산자 종류


0. Go 학습 재개


원래 스터디 당초 계획은 3일에 한 번씩 진도를 나가는 것이었으나 …
졸업 작품 + 취업 과제, 면접으로 인해 한 달이 쫙 밀려버렸다.
나 대신 스터디를 진행해준 스터디원의 양해에 감사하며 다시 열심히 해봐야겠다.

1. 연산자 종류


어떤 언어를 배우든 그에 맞는 연산자가 존재한다.
Go 에서의 여러가지 연산자에 대해서 알아보자.

I. 수식 연산자


수식 연산자는 두 개의 피연산자를 요구하는 이항 연산자(binary operator)이다.
다른 언어들과 마찬가지로 기본적인 사칙연산, 나머지 값 반환 연산자가 있다.

종류기능설명
+피연산자의 값을 더한다.값의 자료형은 정수, 실수, 복소수, 문자열입니다.
-왼쪽의 피연산자 값에서 오른쪽의 피연산자 값을 뺀다.값의 자료형은 정수, 실수, 복소수입니다.
*피연산자의 값을 곱한다.값의 자료형은 정수, 실수, 복소수입니다.
/왼쪽의 피연산자 값을 오른쪽의 피연산자 값으로 나눈다.값의 자료형은 정수, 실수, 복소수입니다.
%왼쪽의 피연산자 값을 오른쪽의 피연산자 값으로 나눴을 때 얻게 되는 나머지 값을 반환한다.
ex) num := 7 % 2
(num = 1이 할당됨)
값의 자료형은 정수, 실수, 복소수입니다.

+ 연산자는 문자열 결합도 가능함에 주의.

package main

import "fmt"

func main() {
	num1, num2 := 17, 5
	str1, str2 := "Hello", "goorm!"
	
	fmt.Println("num1 + num2 =", num1+num2)
	fmt.Println("str1 + str2 =", str1+str2)
	fmt.Println("num1 - num2 =", num1-num2)
	fmt.Println("num1 * num2 =", num1*num2)
	fmt.Println("num1 / num2 =", num1/num2)
	fmt.Println("num1 % num2 =", num1%num2)
}
// 실행결과
num1 + num2 = 22
str1 + str2 = Hellogoorm!
num1 - num2 = 12
num1 * num2 = 85
num1 / num2 = 3
num1 % num2 = 2

II. 증감 연산자


C++과 동일하지만, 주의할 점이 있다.

  1. 증감 연산자를 사용함과 동시에 대입할 수 없다.
    • ex) num := count++ (X)
  2. 전위 연산을 할 수 없다.
    • ex) ++count (X)
종류기능설명
++값을 1 증가시킨다.값의 자료형은 정수, 실수, 복소수입니다.
값을 1 감소시킨다.값의 자료형은 정수, 실수, 복소수입니다.
package main

import "fmt"

func main() {
	count1, count2 := 1, 10.4
	
	count1++
	count2--
	
	fmt.Println("count1++ :", count1)
	fmt.Println("count2-- :", count2)
}
// 실행결과
count1++ : 2
count2-- : 9.4

III. 할당 연산자


할당 연산자는 값을 단순히 대입하는 대입 연산자와 연산 후 값을 바로 대입시키는 복합 대입 연산자가 있다.

다른 언어와 거의 동일하다.

종류기능설명
=변수나 상수에 값을 대입한다.변수는 변수끼리 대입이 가능합니다.
:=변수를 선언 및 대입한다. 
:=변수를 선언 및 대입한다. 
+=값을 더한 후 대입한다.문자열일 경우 현재 변수에 문자열을 이어 붙인 다음 변수에 대입합니다.
*=값을 곱한 후 대입한다. 
/=값을 나눈 후 대입한다. 
%=값의 나눗셈 후 나머지를 대입한다. 
&=값의 AND 비트 연산 후 대입한다. 
|=값의 OR 비트 연산 후 대입한다. 
^=값의 XOR 비트 연산 후 대입한다. 
&^=값의 AND NOT 비트 연산 후 대입한다. 
«=비트를 왼쪽으로 이동 후 대입한다. 
»=비트를 오른쪽으로 이동 후 대입한다. 
package main

import "fmt"

func main() {
	a := 2
	var num int

	num = a
	fmt.Println("num = a :", num)
	num += 4
	fmt.Println("num += 4 :", num)
	num -= 2
	fmt.Println("num -= 2 :", num)
	num *= 5
	fmt.Println("num *= 5 :", num)
	num /= 2
	fmt.Println("num /= 2 :", num)
	num %= 3
	fmt.Println("num %= 3 :", num)

	num = 3  //00000011
	num &= 2 //00000010
	fmt.Printf("num &= 2 : %08b, %d\n", num, num)
	num |= 5 //00000101
	fmt.Printf("num |= 5 : %08b, %d\n", num, num)
	num ^= 4 //00000100
	fmt.Printf("num ^= 4 : %08b, %d\n", num, num)
	num &^= 2 //00000010
	fmt.Printf("num &^= 2 : %08b, %d\n", num, num)
	num <<= 9 //00001001
	fmt.Printf("num <<= 9 : %08b, %d\n", num, num)
	num >>= 8 //00001000
	fmt.Printf("num >>= 8 : %08b, %d\n", num, num)
}
// 실행결과
num = a : 2
num += 4 : 6
num -= 2 : 4
num *= 5 : 20
num /= 2 : 10
num %= 3 : 1
num &= 2 : 00000010, 2
num |= 5 : 00000111, 7
num ^= 4 : 00000011, 3
num &^= 2 : 00000001, 1
num <<= 9 : 1000000000, 512
num >>= 8 : 00000010, 2

IV. 논리 연산자


AND(논리곱), OR(논리합), NOT(논리부정)을 연산한다.

마찬가지로 다른 언어들과 거의 동일하다.
주의할 점은 Go 에서는 NOT 연산시 bool 형의 선언 및 사용만이 가능하다.
즉, false , true 값만 사용할 수 있다.
아래 예시를 보자.

var a int = 10, b := 1

fmt.Println(!a) // 불가능
fmt.Println(!b) // 불가능
종류기능설명
&&연산하는 A와 B모두 ‘참’이면 연산 결과로 ‘참’을 반환한다.1&&0=0
1&&1=1
0&&0=0
||연산하는 A와 B 둘 중 하나라도 ‘참’이면 연산 결과로 ‘참’을 반환한다.1||0=1
1||1=1
0||0=0
!연산하는 A가 ‘참’이면 ‘거짓’, ‘거짓’이면 ‘참’을 반환한다.!1=0
!0=1
package main

import "fmt"

func main() {
	var a bool = true
	b := false

	fmt.Println("0 && 0 : ", b && b)
	fmt.Println("0 && 1 : ", b && a)
	fmt.Println("1 && 1 : ", a && a)
	fmt.Println("0 || 0 : ", b || b)
	fmt.Println("0 || 1 : ", b || a)
	fmt.Println("1 || 1 : ", a || a)

	fmt.Println("!1 ", !true)
	fmt.Println("!0 ", !false)
}
// 실행결과

0 && 0 :  false
0 && 1 :  false
1 && 1 :  true
0 || 0 :  false
0 || 1 :  true
1 || 1 :  true
!1  false
!0  true

V. 관계 연산자


관계 연산자는 두 값의 대소와 동등의 관계를 따지는 연산자이다.
관계 연산자는 조건을 만족하면 true를, 만족하지 않으면 false를 반환한다.

종류기능설명
==두 값이 같은지 비교한다.같을 경우 ‘true’, 다를 경우 ‘false’를 반환한다.
!=두 값이 다른지 비교한다.다를 경우 ‘true’, 같을 경우 ‘false’를 반환한다.
<오른쪽 값이 큰지 비교한다.오른쪽 값이 큰 경우 ‘true’, 그렇지 않을 경우 ‘false’를 반환한다.
<=오른쪽 값이 크거나 같은지 비교한다.오른쪽 값이 크거나 같은 경우 ‘true’, 그렇지 않을 경우 ‘false’를 반환한다.
>왼쪽 값이 큰지 비교한다.왼쪽 값이 큰 경우 ‘true’, 그렇지 않을 경우 ‘false’를 반환한다.
>=왼쪽 값이 크거나 같은지 비교한다.왼쪽 값이 크거나 같은 경우 ‘true’, 그렇지 않을 경우 ‘false’를 반환한다.
package main

import "fmt"

func main() {
	fmt.Println("13 == 13 : ", 13 == 13)
	fmt.Println("13 == 23 : ", 13 == 23)
	fmt.Println("13 != 13 : ", 13 != 13)
	fmt.Println("3 != 5 : ", 3 != 5)
	fmt.Println("0 < 1 : ", 0 < 1)
	fmt.Println("0 > 1 : ", 0 > 1)
	fmt.Println("0 >= 1 : ", 0 >= 1)
	fmt.Println("0 <= 1 : ", 0 <= 1)
}
// 실행 결과

13 == 13 :  true
13 == 23 :  false
13 != 13 :  false
3 != 5 :  true
0 < 1 :  true
0 > 1 :  false
0 >= 1 :  false
0 <= 1 :  true

VI. 비트 연산자


비트 연산자는 비트 단위의 연산을 수행한다.
나한테는 PS를 할 때 비트마스킹 등으로 익숙하다.

종류기능설명
&두 값을 비트 단위로 AND 연산을 한다. 
|두 값을 비트 단위로 OR 연산을 한다. 
^두 값을 비트 단위로 XOR 연산을 한다.사용할 수 있는 값의 자료형은 정수입니다.
&^두 값을 비트 단위로 AND NOT 연산을 한다.사용할 수 있는 값의 자료형은 정수입니다.
«값의 비트 열을 왼쪽으로 이동시킨다.사용할 수 있는 값의 자료형은 정수입니다.
»값의 비트 열을 오른쪽으로 이동시킨다.사용할 수 있는 값의 자료형은 정수입니다.
package main

import "fmt"

func main() {
	num1 := 15 //00001111
	num2 := 20 //00010100

	fmt.Printf("num1 & num2 : %08b, %d\n", num1&num2, num1&num2)
	fmt.Printf("num1 | num2 : %08b, %d\n", num1|num2, num1|num2)
	fmt.Printf("num1 ^ num2 : %08b, %d\n", num1^num2, num1^num2)
	fmt.Printf("num1 &^ num2 : %08b, %d\n", num1&^num2, num1&^num2)

	fmt.Printf("num1 << 4 : %08b, %d\n", num1<<4, num1<<4)
	fmt.Printf("num2 >> 2 : %08b, %d\n", num2>>2, num2>>2)
}
// 실행 결과

num1 & num2 : 00000100, 4
num1 | num2 : 00011111, 31
num1 ^ num2 : 00011011, 27
num1 &^ num2 : 00001011, 11
num1 << 4 : 11110000, 240
num2 >> 2 : 00000101, 5

VII. 채널 연산자


Go 언어에는 채널 이라는 개념이 있다.
간단히 말하자면 채널이랑 고루틴(goroutine)끼리 데이터를 주고 받고 실행 흐름을 제어하는 기능이다.
채널 연산자채널을 사용할때 쓰는 연산자이다.

처음으로 아예 색다른 연산자가 나왔다.
지금은 그런가보다 하고 넘어가고 채널에 대해 자세한건 이후에 배워보자.

종류기능설명
<-채널의 수신을 연산한다.채널에 값을 보내거나 가져옵니다.
package main

import "fmt"

func main() {
	ch := make(chan int) //정수형 채널 생성

	go func() {
		ch <- 10
	}() //채널에 10을 보냄

	result := <-ch //채널로부터 10을 전달받음
	fmt.Println(result)
}
// 실행 결과

10

VIII. 포인터 연산자


포인터 연산자는 C++과 같이 &*연산자를 이용해 메모리에 접근할 수 있도록 한다.
주의할 점은 Go언어는 포인터 연산자를 제공하지만 포인터 산술 즉, 포인터에 더하고 빼는 기능은 제공하지 않는다.

종류기능설명
&변수의 메모리 주소를 참조한다. 
*포인터 변수에 저장된 메모리에 접근하여 값을 참조한다. 
package main

import "fmt"

func main() {
	var num int = 5
	var pnum = &num

	fmt.Println("num : ", num)   //num 값
	fmt.Println("pnum :", pnum)  //num의 메모리 주소
	fmt.Println("pnum :", *pnum) //num의 주소로 메모리에 할당돼있는 값 접근

	*pnum++
	fmt.Println("num : ", num)
	fmt.Println("pnum :", *pnum)
	//포인터 연산자를 이용한 값 변경
}
// 실행 결과

num :  5
pnum : 0xc0000160c8
pnum : 5
num :  6
pnum : 6

마무리


대부분의 연산자는 다른 언어들에서 최소 한 번씩은 본 연산자들이지만, 채널 연산자 는 처음이라 조금 색달랐다.

다른건 없고, 증감 연산자 , 논리 연산자 , 포인터 연산자 의 주의사항 정도만 확인하고 넘어가면 될 것 같다.


© 2022. All rights reserved.