Do it! Go 완전 정복

코드는 예술이다. 여러분의 작품으로 세상에 영감을 불어넣어라.

Do it! Go 완전 정복, 머리말

1장. Go 시작하기 #

Go는 컴파일을 해야 하는 정적 언어다. 컴파일 시간 단축을 목적으로 문법 구조부터 다른 언어와 다르게 설계되어서 컴파일도 빠르다. 이를 위해 Go는 객체지향 프로그래밍의 많은 기능을 포기했다. 그만큼 단순하며 예약어도 25개뿐이다.

Go는 도커, 쿠버네티스, 코크로치 DB, TS컴파일러(TS진영에선 이것의 go 포팅이 상당히 말이 많았다) 등 대형 프로젝트에서 사용되고 있다. 한때 프론트에서도 esbuild처럼 여러 프로젝트를 Go로 재작성하는 게 한창 유행이었다. 언어만 바꿨는데 속도가 올라간다구요. 구글에서도 내부적으로 Go를 많이 사용한다고 한다.

Go 공식 홈페이지에서 go를 설치할 수 있다.

go version # Go 버전 확인

나는 vscode의 go 익스텐션도 설치했다.

Go로 작성된 hello world

package main

import "fmt"

func main() {
	fmt.Println("Hello, World!")
}

이렇게 하고 빌드하면 실행 파일을 생성할 수 있다. C언어를 배우던 시절이 오랜만에 떠오른다.

go build 파일명
./파일명 # 실행

Go에서 제공하는 명령어들. 앞에서 go version이랑 go build를 사용했는데, 그 외에도 유용한 명령어들이 많다.

2장. Go 프로그래밍 준비하기 #

패키지는 go 코드의 기본 단위다. 프로그램은 패키지 단위로 개발하며 모든 코드 파일의 첫 줄에는 이 코드가 어떤 패키지에 속하는지를 명시해야 한다. 또 같은 디렉토리에 있으면 같은 패키지에 속해야 한다(안 그러면 package 선언에서 에러 발생)

이때 main 패키지는 특별 취급으로 package main으로 선언된 패키지는 프로그램의 진입점인 main 함수를 포함해야 한다. 따라서 main 패키지는 독립적으로 실행 가능한 프로그램을 만들 때 사용한다.

외부 패키지 내려받으려면 go get <패키지명>

혹은 소스 파일에서 먼저 import 한 다음 go mod tidy를 사용하면 사용하지 않는 패키지는 go.mod에서 제거되고 필요한 패키지는 자동으로 설치된다. 이런 외부 패키지는 모듈 캐시에 저장되고 go env GOMODCACHE로 지정된 디렉토리에 설치된다. 캐시 정리는 go clean -modcache로 할 수 있다.

환경 변수 GOROOT, GOPATH #

GOROOT 환경 변수는 which go로 go 실행 파일 위치 확인. 그러면 /usr/local/go/bin/go 같은 경로가 나오는데, 이때 GOROOT/usr/local/go가 된다. Go 설치 디렉토리를 가리킨다. 이걸 .bash_profile 같은 쉘 설정 파일에 추가하면 된다.

vi ~/.zshrc # export GOROOT=/usr/local/go 추가 후 저장
source ~/.zshrc # 변경 사항 적용

go 1.16까지는 GOPATH 라는 환경 변수로 프로젝트와 의존성을 관리했다. go 프로젝트를 수행할 작업 공간(workspace) 경로를 지정하는 환경 변수다. GOPATH는 기본적으로 ~/go로 설정되어 있다. 아무튼 원하는 워크스페이스 경로를 위와 같은 방식으로 쉘 설정에 GOPATH 환경 변수로 추가하면 된다.

외부 패키지 사용하기 #

폴더 만들고 모듈로 만들기

mkdir myproject
cd myproject
go mod init myproject
# 깃헙에서 패키지 다운로드. 모듈 캐시에 저장됨
go get github.com/fatih/color

다음과 같이 import 해서 사용할 수 있다. 이때 import된 패키지들은 큰따옴표로 묶어서 작성하고 쉼표로 구분하지 않는다.

package main

import (
	"fmt"

	"github.com/fatih/color"
)

func main() {
	fmt.Printf("%v %v\n", color.RedString("Hello"), color.GreenString("World"))
}

go run hello.go로 실행하면 빨간색과 초록색으로 Hello World가 출력된다.

3장. 변수와 상수 #

go의 주석은 JS랑 똑같다. //로 한 줄 주석, /* */로 여러 줄 주석을 작성할 수 있다.

변수 선언은 다음과 같은 형태로 할 수 있다.

var 변수명 타입
var age int = 30 // 예시. 근데 이런 식으로 초기값을 대입하면 타입은 생략 가능
var name = "Alice" // 타입 생략. 컴파일러가 초기값으로부터 타입 추론

walrus 연산자 :=를 사용하면 변수 선언과 초기화를 동시에 할 수 있다. 이때 타입은 생략해야 하며 컴파일러의 타입 추론을 위해 초기값을 반드시 제공해야 한다. 반드시 함수 내부에서만 사용할 수 있다.

// 변수명 := 초기값
total := 1

python 스타일로 여러 변수 한 번에 선언할 수도 있다. 혹은 var 이후에 ()로 묶어서 여러 변수를 한 번에 선언할 수도 있다.

var a,b,c=1,2,3
a, b, c := 1, 2, 3 // walrus 연산자도 여러 변수에 동시에 사용할 수 있다.
// 괄호로 묶어서 한 번에 선언하기
var (name="Kim Sunghyun"
  age=30)

fmt.Printf("My name is %s and I'm %d years old.\n", name, age)

변수명 규칙은 다른 언어와 다 비슷하다. 예약어 못 쓰고, 공백이나 특수문자 안되고, 문자나 밑줄로만 시작할 수 있고 등등.

변수의 자료형 #

변수 선언 시 초기값을 지정하면 컴파일러가 자동으로 추론하지만, 초기값이 없는 경우에는 명시적으로 자료형을 지정해야 한다.

// var 변수명 자료형 같은 형식
var age int32
var pi float64

변수 스코프 #

지역 변수는 {}로 묶인 블록 내부에서 선언된 변수로, 해당 블록 내에서만 접근할 수 있다. 이렇게 {}로 묶인 블록은 스코프를 만드는데, 함수, 조건문, 반복문 등에서 사용할 수 있다. 참고로 이런 중괄호는 함수 선언이나 제어문에서만 쓸 수 있는 게 아니라 그냥도 쓸 수 있다.

func main(){
	{
		a:= 10
		fmt.Printf("a: %d\n", a)
	}
	fmt.Printf("a: %d\n", a) // 에러. a는 중괄호로 묶인 블록 내부에서 선언된 지역 변수이므로 블록 외부에서는 접근할 수 없다.
}

전역 변수는 어떤 스코프에도 속하지 않으면서 패키지 수준에서 선언된 변수로 패키지 내 모든 곳에서 접근 가능하다. 그냥 제일 바깥에서 선언하면 됨.

C언어랑 비슷하게 전역 변수는 데이터 영역, 지역 변수와 매개변수 같은 건 스택 영역에 저장된다. 또한 지역 변수 스코프의 같은 이름의 변수가 전역 변수를 shadowing할 수 있는 것도 똑같음.

출력 함수 #

출력시 %s 같은 서식 지정자를 사용할 수 있다. 서식 지정자는 c에서처럼 값의 출력 형태를 지정한다.

fmt.Printf("안녕하세요, %s\n", "Go 언어")

이런 서식 지정자를 쓸 수 있는 출력 함수랑 아닌 게 나뉘어 있는데, fmt.Printf는 서식 지정자를 사용할 수 있지만 fmt.Println은 서식 지정자를 지원하지 않는다. 또한 fmt.Println은 자동으로 줄바꿈 추가.

상수 #

JS에서처럼 go에서도 const로 상수 선언할 수 있다. Go의 상수는 반드시 초깃값을 지정해야 한다.

func main(){
	const PI = 3.14

	fmt.Printf("PI: %v\n", PI)
}

앞서서처럼 여러 개 한번에 선언도 똑같이 가능

const a,b,c = 1,2,3