연산자 알아보기

이재홍 http://www.pyrasis.com 2014.12.17 ~ 2015.02.07

이번에는 Go 언어에서 사용할 수 있는 연산자에 대해 알아보겠습니다. 표로는 내용이 길지만 모두 외울 필요는 없습니다. 언제든 필요할 때 찾아보기 바랍니다.

연산자 기능 설명
= 대입 변수나 상수에 값을 대입합니다. 변수는 변수끼리 대입할 수 있습니다.
var a int = 1
var b int = 2
var c int = b
const d string = "Hello, world!"
:= 변수 선언 및 대입 변수를 선언하는 동시에 값을 대입합니다.
a := 1               // int
b := 3.5             // float64
c := "Hello, world!" // string
+ 덧셈 두 값을 더합니다. 사용할 수 있는 자료형은 정수, 실수, 복소수, 문자열입니다.
a := 1 + 2                // 3: 두 정수 더하기
b := 2 + 3                // 5: 두 정수 더하기
c := a + b                // 8: 두 변수 더하기
d := "Hello, " + "world!" // Hello, world!: 두 문자열 붙이기
- 뺄셈 두 값의 차이를 구합니다. 사용할 수 있는 자료형은 정수, 실수, 복소수입니다.
a := 3 - 2 // 1: 두 정수 빼기
b := 4 - 5 // -1: 두 정수 빼기
c := a - b // 2: 두 변수 빼기
* 곱셈 두 값을 곱합니다. 사용할 수 있는 자료형은 정수, 실수, 복소수입니다.
a := 2 * 3  // 6: 두 정수 곱하기
b := 9 * 21 // 189: 두 정수 곱하기
c := a * b  // 1134: 두 변수 곱하기
/ 나눗셈 두 값을 나눕니다. 사용할 수 있는 자료형은 정수, 실수, 복소수입니다.
a := 5 / 2  // 2: 두 정수 나누기
b := 12 / 4 // 3: 두 정수 나누기
c := a / b  // 0: 두 변수 나누기
% 나머지 두 값을 나눈 뒤 나머지를 구합니다. 사용할 수 있는 자료형은 정수입니다.
a := 5 % 2 // 1: 5를 2로 나누었을 때 나머지 구하기
+= 덧셈 후 대입 현재 변수와 값을 더한 다음 다시 변수에 대입합니다. 문자열은 현재 변수에 문자열을 붙인 다음 다시 변수에 대입합니다.
a := 5         // 5
a += 2         // 7: a에 2를 더한 후 대입
fmt.Println(a) // 7
a := "Hello, " // Hello,
a += "world!"  // Hello, world!: a에 world! 문자열을 붙인 후 대입
fmt.Println(a) // Hello, world!
-= 뺄셈 후 대입 현재 변수에서 값을 뺀 다음 다시 변수에 대입합니다.
a := 5         // 5
a -= 2         // 3: a에 2를 뺀 후 대입
fmt.Println(a) // 3
*= 곱셈 후 대입 현재 변수와 값을 곱한 다음 다시 변수에 대입합니다.
a := 5         // 5
a *= 2         // 10: a에 2를 곱한 후 대입
fmt.Println(a) // 10
/= 나눗셈 후 대입 현재 변수를 값으로 나눈 다음 다시 변수에 대입합니다.
a := 5         // 5
a /= 2         // 2: a에 2를 나눈 후 대입
fmt.Println(a) // 2
%= 나머지를 구한 후 대입 현재 변수와 값의 나머지를 구한 다음 다시 변수에 대입합니다.
a := 5         // 5
a %= 2         // 1: a에서 2를 나눈 후 나머지를 대입
fmt.Println(a) // 1
& AND 비트 연산 두 값을 비트 단위로 AND 연산을 합니다. 사용할 수 있는 자료형은 정수입니다.
a := 3                // 00000011
b := 2                // 00000010
c := a & b            // 00000010: a와 b의 AND 비트 연산
fmt.Printf("%08b", c) // 00000010
| OR 비트 연산 두 값을 비트 단위로 OR 연산을 합니다. 사용할 수 있는 자료형은 정수입니다.
a := 3                // 00000011
b := 2                // 00000010
c := a | b            // 00000011: a와 b의 OR 비트 연산
fmt.Printf("%08b", c) // 00000011
^ XOR 비트 연산(다항) 두 값을 비트 단위로 XOR 연산을 합니다. 사용할 수 있는 자료형은 정수입니다.
a := 3                // 00000011
b := 2                // 00000010
c := a ^ b            // 00000001: a와 b의 XOR 비트 연산
fmt.Printf("%08b", c) // 00000001
&^ AND NOT 비트 연산 두 값을 비트 단위로 AND NOT 연산을 합니다. 즉 다음과 같이 특정 비트를 끕니다(Bit clear). 사용할 수 있는 자료형은 정수입니다.
a := 255              // 11111111
b := 68               // 01000100
c := a &^ b           // 10111011: a와 b의 AND NOT 비트 연산
fmt.Printf("%08b", c) // 10111011
&= AND 비트 연산 후 대입 현재 변수를 값으로 AND 연산한 다음 다시 변수에 대입합니다.
a := 3                // 00000011
b := 2                // 00000010
a &= b                // 00000010: a와 b를 AND 비트 연산 후 a에 대입
fmt.Printf("%08b", a) // 00000010
|= OR 비트 연산 후 대입 현재 변수를 값으로 OR 연산한 다음 다시 변수에 대입합니다.
a := 3                // 00000011
b := 2                // 00000010
a |= b                // 00000011: a와 b를 OR 비트 연산 후 a에 대입
fmt.Printf("%08b", a) // 00000011
^= XOR 비트 연산 후 대입 현재 변수를 값으로 XOR 연산한 다음 다시 변수에 대입합니다.
a := 3                // 00000011
b := 2                // 00000010
a ^= b                // 00000001: a와 b를 XOR 비트 연산 후 a에 대입
fmt.Printf("%08b", a) // 00000001
&^= AND NOT 비트 연산 후 대입 현재 변수를 값으로 AND NOT 연산한 다음 다시 변수에 대입합니다. 이 연산자는 특정 플래그를 끌 때 주로 사용합니다.
a := 255              // 11111111
b := 68               // 01000100
a &^= b               // 10111011: a와 b를 AND NOT 비트 연산 후 a에 대입
fmt.Printf("%08b", a) // 10111011
<< 비트를 왼쪽으로 이동 현재 값의 비트를 특정 횟수만큼 왼쪽으로 이동합니다. 사용할 수 있는 자료형은 정수입니다.
a := 7                // 00000111
b := a << 2           // 00011100: a의 비트를 오른쪽으로 2번 이동
fmt.Printf("%08b", b) // 00011100
>> 비트를 오른쪽으로 이동 현재 값의 비트를 특정 횟수만큼 오른쪽으로 이동합니다. 사용할 수 있는 자료형은 정수입니다.
a := 112              // 01110000
b := a >> 3           // 00001110: a의 비트를 왼쪽으로 3번 이동
fmt.Printf("%08b", b) // 00001110
<<= 비트를 왼쪽으로 이동 후 대입 현재 변수를 특정 횟수만큼 왼쪽으로 이동한 다음 다시 변수에 대입합니다.
a := 7                // 00000111
a <<= 2               // 00011100: a의 비트를 왼쪽으로 2번 이동한 후 a에 대입
fmt.Printf("%08b", a) // 00011100
>>= 비트를 오른쪽으로 이동 후 대입 현재 변수를 특정 횟수만큼 오른쪽으로 이동한 다음 다시 변수에 대입합니다.
a := 112              // 01110000
a >>= 3               // 00001110: a의 비트를 오른쪽으로 3번 이동한 a에 후 대입
fmt.Printf("%08b", a) // 00001110
^ 비트 반전(단항) 비트를 반전시킵니다(Bitwise complement, 1의 보수). 즉 0은 1로 1은 0으로 바꿉니다.
var a uint8 = 3       // 00000011
b := ^a               // 11111100: a의 비트를 반전시김
fmt.Printf("%08b", b) // 11111100
+ 양수 부호(단항) 값에 양수 부호를 붙입니다.
a := 3
b := -2
c := +a        // a에 양수 부호를 붙임
d := +b        // b에 양수 부호를 붙임
fmt.Println(c) // 3: +(3)
fmt.Println(d) // -2: +(-2)
- 음수 부호 (단항) 값에 음수 부호를 붙입니다.
a := 3
b := -2
c := -a        // a에 음수 부호를 붙임
d := -b        // b에 음수 부호를 붙임
fmt.Println(c) // -3: -(3)
fmt.Println(d) // 2: -(-2)
== 같다 두 값이 같은지 비교합니다.
  • 실수형은 값을 연산한 뒤에는 오차가 발생하므로 ==로 비교할 때 주의해야 합니다.
  • 문자열은 내용이 같은지 비교합니다.
  • 배열은 요소의 내용이 모두 같은지 비교합니다.
  • 슬라이스와 맵은 배열과는 달리 내용을 비교할 수 없고, 메모리에 할당되어 있는지 확인합니다.
  • 포인터는 주소가 같은지 비교합니다.
fmt.Println(1 == 1)             // true: 두 정수가 같으므로 true
fmt.Println(3.5 == 3.5)         // true: 두 실수가 같으므로 true
fmt.Println("Hello" == "Hello") // true: 두 문자열이 같으므로 true

a := [3]int{1, 2, 3}
b := [3]int{1, 2, 3}
fmt.Println(a == b) // true: 두 배열이 같으므로 true

c := []int{1, 2, 3}
fmt.Println(c == nil) // false: 슬라이스를 nil과 비교하여 
                      // 메모리가 할당되었는지 확인

d := map[string]int{"Hello": 1}
fmt.Println(d == nil) // false: 맵을 nil과 비교하여 
                      // 메모리가 할당되었는지 확인

e := 1
var p1 *int = &e
var p2 *int = &e
fmt.Println(p1 == p2) // true: 포인터에 저장된 메모리 주소가 같으므로 true
!= 같지 않다 두 값이 다른지 비교합니다.
fmt.Println(1 != 2)             // true: 두 정수가 다르므로 true
fmt.Println(3.5 != 5.5)         // true: 두 실수가 다르므로 true
fmt.Println("Hello" != "world") // true: 두 문자열이 다르므로 true

a := [3]int{1, 2, 3}
b := [3]int{3, 2, 1}
fmt.Println(a != b) // true: 두 배열이 다르므로 true

c := []int{1, 2, 3}
fmt.Println(c != nil) // true: 슬라이스를 nil과 비교하여 
                      // 메모리가 할당되었는지 확인

d := map[string]int{"Hello": 1}
fmt.Println(d != nil) // true: 맵을 nil과 비교하여 
                      // 메모리가 할당되었는지 확인

e := 1
f := 1
var p1 *int = &e
var p2 *int = &f
fmt.Println(p1 != p2) // true: 포인터에 저장된 메모리 주소가 다르므로 true
< 작다 앞의 값이 작은지 비교합니다. 문자열은 ASCII 코드 값을 기준으로 판단합니다. 또한, 첫 글자가 같다면 그 다음 글자부터 차례대로 비교하여 최종 값을 구합니다.
fmt.Println(1 < 2)             // true: 1이 2보다 작으므로 true
fmt.Println(3.5 < 5.5)         // true: 3.5가 5.5보다 작으므로 true
fmt.Println("Hello" < "world") // true: H가 w보다 ASCII 코드 값이 
                               // 작으므로 true
<= 작거나 같다 앞의 값이 작거나 같은지 비교합니다.
fmt.Println(2 <= 2)             // true: 2가 2보다 작거나 같으므로 true
fmt.Println(3.5 <= 5.5)         // true: 3.5가 5.5보다 작거나 같으므로 true
fmt.Println("Hello" <= "world") // true: H가 w보다 ASCII 코드 값이 
                                // 작거나 같으므로 true
> 크다 앞의 값이 큰지 비교합니다.
fmt.Println(2 > 1)             // true: 2가 1보다 크므로 true
fmt.Println(5.5 > 3.5)         // true: 5.5가 3.5보다 크므로 true
fmt.Println("world" > "Hello") // true: w가 H보다 ASCII 코드 값이 크므로 true
>= 크거나 같다 앞의 값이 크거나 같은지 비교합니다.
fmt.Println(2 >= 2)             // true: 2가 2보다 크거나 같으므로 true
fmt.Println(5.5 >= 3.5)         // true: 5.5가 3.5보다 크거나 같으므로 true
fmt.Println("world" >= "Hello") // true: w가 H보다 ASCII 코드 값이 
                                // 크거나 같으므로 true
&& AND 논리 연산 두 불 값이 모두 참인지 확인합니다.
fmt.Println(true && true)   // true: 두 값이 모두 true이므로 true
fmt.Println(true && false)  // false: 두 값 중 하나가 false이므로 false
fmt.Println(false && false) // false: 두 값이 모두 false이므로 false
|| OR 논리 연산 두 불 값 중 한 개라도 참인지 확인합니다.
fmt.Println(true || true)   // true: 두 값이 모두 true이므로 true
fmt.Println(true || false)  // true: 두 값 중 하나가 true이므로 true
fmt.Println(false || false) // false: 두 값이 모두 false이므로 false
! NOT 논리 연산 불값을 반대로 연산합니다.
fmt.Println(!true)  // false: true의 반대는 false
fmt.Println(!false) // true: false의 반대는 true
& 참조(레퍼런스) 연산 현재 변수의 메모리 주소를 구합니다.
a := 1
b := &a        // a의 메모리 주소를 b에 대입
fmt.Println(b) // 0xc0820062d0 (메모리 주소)
* 역참조 연산 현재 포인터 변수에 저장된 메모리에 접근하여 값을 가져오거나 저장합니다.
a := new(int)
*a = 1          // a에 저장된 메모리에 접근하여 1을 저장
fmt.Println(*a) // 1: a에 저장된 메모리에 접근하여 값을 가져옴
<- 채널 수신 연산 채널에 값을 보내거나 값을 가져옵니다.
c := make(chan int)

go func() {
	c <- 1 // 채널 c에 1을 보냄
}()

a := <-c       // 채널 c에서 값을 가져와서 a에 대입
fmt.Println(a) // 1
++ 증가 변수의 값을 1 증가시킵니다. 사용할 수 있는 자료형은 정수, 실수, 복소수입니다.
a := 1
a++ // 2: 정수 1을 1 증가시켜서 2

b := 1.5
b++ // 2.5: 실수 1.5를 1 증가시켜서 2.5

c := 1 + 2i
c++ // (2+2i): 복소수 1+2i를 1 증가시켜서 2+2i

fmt.Println(a) // 2
fmt.Println(b) // 2.5
fmt.Println(c) // (2+2i)
Go 언어에서는 ++ 연산자를 사용한 뒤 값을 대입할 수 없고, 변수 뒤에서만 사용할 수 있습니다. 따라서 ++ 연산자는 단독으로 사용하거나 if 조건문, for 반복문 안에서 주로 사용합니다.
a := 1
b := a++ // 컴파일 에러
c := ++a // 컴파일 에러
++a      // 컴파일 에러
-- 감소 변수의 값을 1 감소시킵니다. 사용할 수 있는 자료형은 정수, 실수, 복소수입니다.
a := 1
a-- // 0: 정수 1을 1 감소시켜서 0

b := 1.5
b-- // 0.5: 실수 1.5를 1 감소시켜서 0.5

c := 1 + 2i
c-- // (0+2i): 복소수 1+2i를 1 감소시켜서 0+2i

fmt.Println(a) // 0
fmt.Println(b) // 0.5
fmt.Println(c) // (0+2i)
Go 언어에서는 -- 연산자를 사용한 뒤 값을 대입할 수 없고, 변수 뒤에서만 사용할 수 있습니다. 따라서 -- 연산자는 단독으로 사용하거나 if 조건문, for 반복문 안에서 주로 사용합니다.
a := 1
b := a-- // 컴파일 에러
c := --a // 컴파일 에러
--a      // 컴파일 에러

표 13-1 Go 언어의 연산자 종류


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

01 June 2015