Golang
Go란?
Go(또는 Golang)는 Google이 2009년에 발표한 Open Source Programming Language이다.
간결함, 가독성, C 계열 언어의 성능을 유지하면서도 문법을 대폭 단순화 하였음.
불필요한 Keyword나 복잡한 문법이 없어 코드가 깔끔함.
빠른 Compile 속도로, 대규모 Project도 Compile이 매우 빠르며, 단일 Binary로 Build되어 배포가 쉬움.
동시성(Concurrency) 지원 고루틴(goroutine)과 채널(channel)을 언어 차원에서 지원해, Multithreaded Programming을 쉽고 안전하게 할 수 있음.
다른 언어와 비교

Hello World!
bash# vim main.go
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
bash# go run main.go
Hello World
라인 하나하나 설명 해보도록 함.
package main
이것은 Package Declaration(패키지 선언)이다.
모든 Go 프로그램은 반드시 Package Declaration으로 시작해야 한다.
import "fmt"
import keyword는 다른 패키지에 포함된 코드를 이용할 때 쓴다.
fmt 패키지에는 입력과 출력에 대한 형식화가 구현돼 있다.
fmt가 큰따옴표로 둘러쌓여 있다는 점을 보자. 이런 식으로 큰따옴표를 사용하는 것은 문자열 리터럴 이라고 알려져 있으며, 수식(expression)에 해당한다.
Go에서 문자열은 길이가 정해진 문자의 나열을 나타낸다.
func main() {
}
이것은 함수 선언 이다.
함수(function)은 Go 프로그램의 기본 구성 요소다. 함수는 입력과 출력, 그리고 문장(순서대로 실행되는)이라고 하는 일련의 단계를 포함한다. 모든 함수는 func라는 keyword로 시작해 이어서 해당 함수의 이름(이 경우 main), 괄호로 둘러싸인 0개 이상의 매개변수(parameter), 반환형(선택사항), 중괄호로 둘러쌓인 본문(body)이 온다.
이 함수에는 parameter가 없고, 아무것도 반환하지 않으며, 문장만 한 줄 담고 있다.
main이라는 이름은 특별한데, 이 함수는 프로그램을 실행할 때 호출되는 함수이기 때문이다.
fmt.Println("Hello World")
해당 구문은 세 가지 구성요소로 이루어져 있다.
먼저 fmt 패키지 안에 포함된 Println 이라는 함수에 접근한다.
그런 다음 Hello World가 담긴 새 문자열을 생성해서,
해당 문자열을 첫 번째이자 유일한 인자로 함수를 호출한다.
Type
숫자 – 정수
- 소수부가 없는 숫자를 의미함.
- 예를 들면 -3, -2, -1, 0, 1, 2, 3 이 있음.
- Go의 정수 Type은 아래와 같은 종류가 있음.
- uint8
- uint16
- uint32
- uint64
- int8
- int16
- int32
- int64
- 8, 16, 32, 64는 각 Type이 사용하는 Bit의 수를 나타냄.
- uint는 부호가 없는 정수(unsigned integer)를 나타냄.
- 양수 또는 0만 담긴다.
- uint8 = byte 이라고도 부름.
- uint32 = rune 이라고도 부름.
- int는 부호가 있는 정수(signed integer)를 나타냄.
- 일반적으로 정수를 이용할 경우
inttype을 사용하면 될 것.
Example
정수를 사용하는 예제 프로그램 작성
bash# vim main.go
package main
import "fmt"
func main() {
fmt.Println("1 + 1 =", 1 + 1)
}
bash# go run main.go
1 + 1 = 2
이 프로그램은 1 + 1 = 이라는 문자열에 이어 1 + 1 이라는 수식의 결과를 출력한다.
숫자 – 부동소수점 수
- 소수부가 포함된 숫자를 의미함.
- 예를 들면 1.234, 123.4 0.0001234 가 있음.
- 부동 소수점 수는 부정확함.
- 예를 들어
1.01 - 0.99를 계산시0.020000000000000018이 결과로 나타난다.
- 예를 들어
- 정수와 달리 부동소수점 수는 일정한 크기(32bit or 64bit)가 있다.
- 크기가 큰 부동소수점 수를 사용할수록 숫자의 정확도가 높아진다.
- 숫자와 더불어 다른 여러 값도 표현할 수 있는데, 가령 숫자가 아닌 것이나 양의 무한대, 음의 무한대 같은 것이 있다.
- Go에는
float32와float64라는 두 가지 부동소수점 Type을 비롯해complex64와complex128이라고 하는 복소수를 나타내는 두 가지 Type이 있다. - 일반적으로 부동소수점 수를 이용할 때
float64를 사용하면 될 것.
Example
부동소수점 수를 사용하는 예제 프로그램 작성
bash# vim main.go
package main
import "fmt"
func main() {
fmt.Println("1.1 + 1.1 =", 1.1 + 1.1)
}
bash# go run main.go
1.1 + 1.1 = 2.2
이번에는 소수점을 포함한 계산에 성공하였다.
Go에는 덧셈뿐 아니라 다른 여러 연산자도 있다.
| 연산자 | 연산 |
| + | 덧셈 |
| – | 뺄셈 |
| * | 곱셈 |
| / | 나눗셈 |
| % | 나머지 |
문자열
Example
bash# vim main.go
package main
import "fmt"
func main() {
fmt.Println(len("Hello World"))
fmt.Println("Hello World"[0])
fmt.Println("Hello " + "World")
}
bash# go run main.go
11
72
Hello World
- Hello World의 길이 (string의 수)
- Hello World의 0번째 Index 값의
byte값.byte값이란int8을 의미.- 0번째 Index는 H 인데, H는 ASCII 72번 이므로 해당 값이 출력되는것.
Hello와,World를 연산한 결과가 출력됨.- Go compiler는 인자의 Type을 토대로 어떻게 처리할지 판단한다.
+의 양측이 모두 문자열이므로 compiler는 덧셈이 아닌 문자열 연결을 의도한다고 가정함.
- Go compiler는 인자의 Type을 토대로 어떻게 처리할지 판단한다.
Boolean
Boolean 값은 True와 False를 나타내는데 사용되는 특별한 1bit 정수 type이다.
on/off를 나타내기도 한다.
Boolean 값에 대해서는 세가지 연산자가 사용된다.
| 연산자 | 의미 |
| && | and |
| || | or |
| ! | not |
다음은 Boolean 연산자를 어떻게 사용할 수 있는지 보여주는 프로그램이다.
bash# vim main.go
package main
import "fmt"
func main() {
fmt.Println(true && true)
fmt.Println(true && false)
fmt.Println(true || true)
fmt.Println(true || false)
fmt.Println(!true)
}
bash# go run main.go
true
false
true
true
false
Variable
변수는 저장 공간이며 구체적인 Type과 그와 연관된 이름을 가지고 있다.
위에서 작성한 프로그램들이 변수를 사용하도록 수정 해 보겠다.
코드:
package main
import "fmt"
func main() {
var x string = "Hello World"
fmt.Println(x)
}
실행 결과:
Hello World
이번에는 “Hello World”라는 문자열을 x 라는 변수에 할당했다.
그리고 Println 함수가 x 변수에서 값을 가져오도록 하였다.
아래와 같이 사용할 수도 있다.
코드:
package main
import "fmt"
func main() {
var x string
x = "Hello"
fmt.Println(x)
x = x + " World"
fmt.Println(x)
}
실행 결과:
Hello
Hello World
다음 프로그램은 == 기호를 사용하여 2개 값을 비교한 결과를 Boolean Type으로 출력해준다.
package main
import "fmt"
func main() {
var x string = "Hello"
var y string = "World"
fmt.Println(x == y)
}
false
다음 프로그램은 := 를 사용하여 Type을 명시하지 않고 변수를 선언한 것이다.
:= 는 Short Variable Declaration(짧은 변수 선언)이라고 한다.
package main
import "fmt"
func main() {
x := "Hello World"
fmt.Println(x)
}
Hello World
위 x := "Hello World" 는 var x = "Hello World" 와 동일하다고 보면 됨.
Global Variable
아래는 전역 변수(Global Variable)을 사용하여 작성한 프로그램임.
package main
import "fmt"
var x = "Hello World"
func main() {
fmt.Println(x)
}
Hello World
전역 변수를 사용했다는 것은 프로그램 내 어떠한 함수에서도 사용할 수 있는 변수를 지정했다는 것.
반대로 함수 내에 변수 선언을 하는 것을 지역 변수(Local Variable)를 사용했다고 함.
Constant
Go에서도 상수(constant)를 지원한다.
기본적으로 상수는 값이 변경될 수 없다.
상수는 변수와 같은 방식으로 만들어지지만 var keyword를 사용하는 대신 const 라는 keyword를 사용한다.
아래는 const를 사용한 예시 프로그램이다.
package main
import "fmt"
const x = "Hello World"
func main() {
fmt.Println(x)
}
Hello World
아래는 const의 값을 바꾸려고 시도하는 프로그램이다. 에러가 발생하는 것을 확인할 수 있다.
package main
import "fmt"
func main() {
const x = "Hello World"
x = "Some other string"
fmt.Println(x)
}
# command-line-arguments
./main.go:8:2: cannot assign to x (neither addressable nor a map index expression)
여러 개의 변수 정의
아래와 같이 하면 여러개의 변수를 축약된 코드로 정의할 수 있다.
var {
a = 5
b = 10
c = 15
}
예제 프로그램
다음은 사용자가 입력한 숫자를 받아 두 배로 만드는 프로그램이다.
package main
import "fmt"
func main() {
fmt.Print("Enter a number: ")
var input float64
fmt.Scanf("%f", &input)
output := input * 2
fmt.Println(output)
}
Enter a number: 4
8
여기서는 사용자 입력을 읽어들이기 위해 fmt 패키지에서 제공하는 또 다른 함수 Scanf를 사용했다. &input은 Scanf가 우리가 입력한 숫자로 input을 채운다는 것이다.
제어 구조
For
for문을 이용하면 여러 문장(블록)을 여러 번에 걸쳐 반복할 수 있다.
package main
import "fmt"
func main() {
i := 1
for i <= 10 {
fmt.Println(i)
i = i + 1
}
}
1
2
3
4
5
6
7
8
9
10
먼저 출력하고 싶은 숫자를 저장하는 데 사용하는 i라는 변수를 정의하였다.
그런 다음, for 라는 keyword를 사용해 for loop를 작성했는데, true이거나 false가 되는 조건을 지정하고, 마지막으로 실행할 블록을 작성했다.
If
if문을 사용해서 조건을 넣고 true, false에 따른 명령을 실행 해 보도록 하겠다.
위에서 사용한 for문을 응용하여 1부터 10까지 숫자중에 2로 나누어 떨어지는지 여부를 검사하여 홀수, 짝수 여부를 출력 해 보겠다.
package main
import "fmt"
func main() {
for i := 1; i <= 10; i++ {
if i % 2 == 0 {
fmt.Println(i, "짝수")
} else {
fmt.Println(i, "홀수")
}
}
}
1 홀수
2 짝수
3 홀수
4 짝수
5 홀수
6 짝수
7 홀수
8 짝수
9 홀수
10 짝수
Switch
각 숫자에 대한 한글 이름을 출력하는 프로그램이 필요하다고 치자.
if를 사용한다면 다음과 같은 코드로 구현할 수 있다.
package main
import "fmt"
func main() {
var i int
fmt.Print("정수를 입력하세요: ")
fmt.Scanf("%d", &i)
if i == 0 {
fmt.Println("영")
} else if i == 1 {
fmt.Println("일")
} else if i == 2 {
fmt.Println("이")
} else if i == 3 {
fmt.Println("삼")
} else if i == 4 {
fmt.Println("사")
} else if i == 5 {
fmt.Println("오")
}
}
정수를 입력하세요: 5
오
프로그램을 이런 식으로 작성하려면 꽤나 비효율적이라고 볼 수 있다.
그렇기 때문에 Go에서는 이를 더 손쉽게 만들어주는 switch라는 구문을 제공한다.
아래와 같이 작성할 수 있다.
package main
import "fmt"
func main() {
var i int
fmt.Print("정수를 입력하세요: ")
fmt.Scanf("%d", &i)
switch i {
case 0: fmt.Println("영")
case 1: fmt.Println("일")
case 2: fmt.Println("이")
case 3: fmt.Println("삼")
case 4: fmt.Println("사")
case 5: fmt.Println("오")
default: fmt.Println("알 수 없는 숫자")
}
}
정수를 입력하세요: 4
사
switch문은 switch라는 keyword로 시작한 후 수식이 나오고 각 case가 연속해서 나온다.
수식의 값은 각 case keyword 다음에 나오는 수식과 비교된다. 두 수식의 값이 일치하면 : 다음에 나오는 구문이 실행된다.
switch문에서는 값이 일치하는 케이스가 없을 경우 default case도 지원한다. (if문의 else와 비슷)
Array
배열은 길이가 고정된, 번호가 매겨진 단일 타입 원소의 나열이다. Go에서는 다음과 같은 형태를 띤다.
var x [5]int
x는 5개의 int type으로 구성된 array의 예다. 다음 프로그램을 실행해 보자.
package main
import "fmt"
func main() {
var x [5]int
x[4] = 100
fmt.Println(x)
}
[0 0 0 0 100]
x[4] = 100은 배열 x의 5번째 요소를 100으로 설정하라 이다.
다음 프로그램은 시험 점수의 평균을 계산한다.
package main
import "fmt"
func main() {
var x [5]float64
x[0] = 98
x[1] = 93
x[2] = 77
x[3] = 82
x[4] = 83
var total float64 = 0
for _, value := range x {
total += value
}
fmt.Println(total / float64(len(x)))
}
86.6
for _, value := range x 를 사용하면 x array의 값들을 value에 넣어 순회한다.
여기에서 _ 는 배열에서의 index값을 의미하고, value 는 x[i]를 의미한다.
_(underscore)는 compiler에게 이것이 필요하지 않다고 알려주는 데 사용한다.
underscore를 사용한다는 의미는 필요없는 것을 버린다는 뜻이다.
즉 여기서는 첫번째 값(array의 index)을 무시.
Python과는 다르게 _ 변수에 접근이 불가능하다.
Go에서는 배열을 생성하는 더 짧은 문법도 아래와 같이 제공한다.
package main
import "fmt"
func main() {
x := [5]float64{ 98, 93, 77, 82, 83 }
var total float64 = 0
for _, value := range x {
total += value
}
fmt.Println(total / float64(len(x)))
}
아래와 같이 여러 줄로 나눠 써도 된다.
x := [5]float64{
98,
93,
77,
82,
83,
}
마지막 줄 83, 을 보면 comma가 붙어 있다. Go에서는 이렇게 사용해도 문제가 없다고 한다.
=> 이는 특정 줄을 주석 처리할때 특히 유용하다.
Cross Compile
References
더 공부할것
- goroutine
- Multithreaded Programming