Golang 코드의 작성 방법과 관련된 전반적인 내용을 정리합니다.
본 문서는 다음 라이센스를 따릅니다.
https://creativecommons.org/licenses/by/3.0/
이 문서는 간단한 Go 패키지의 개발을 설명하고 Go 패키지와 명령을 가져와서 빌드하고 설치하는 표준 방법인 go 도구를 소개합니다.
go
도구는 구체적인 방법으로 코드를 정리하도록 요구합니다. 문서를 주의깊게 읽으십시오. 이 문서는 Go를 설치하고 실행하는 가장 간단한 방법을 설명합니다.
비슷한 설명을 스크린캐스트로도 볼 수 있습니다.
이는 프로젝트마다 구분된 작업 공간을 가지며 작업 공간들은 버전 관리 저장소와 밀접하게 연결되어 있는 다른 프로그래밍 환경과 다르다는 것을 알아두세요.
작업 공간은 루트에 두 개의 디렉터리를 갖는 디렉터리 계층입니다.
src
는 Go 소스 파일을 가지며,bin
은 실행 가능한 명령을 갖습니다.go
도구는 bin
디렉터리에 바이너리를 빌드하고 설치합니다.
src
서브디렉터리는 주로 하나 이상의 소스 패키지 개발을 추적하는 여러 (Git 또는 Mercurial과 같은)버전 관리 저장소를 갖습니다.
다음은 실제로 작업 공간이 어떻게 구성되는지 이해를 돕기 위한 예시입니다:
bin/
hello # command executable
outyet # command executable
src/
github.com/golang/example/
.git/ # Git repository metadata
hello/
hello.go # command source
outyet/
main.go # command source
main_test.go # test source
stringutil/
reverse.go # package source
reverse_test.go # test source
golang.org/x/image/
.git/ # Git repository metadata
bmp/
reader.go # package source
writer.go # package source
... (many more repositories and packages omitted) ...
위의 트리는 두 개의 저장소(example
과 image
)를 갖는 작업 공간을 보여줍니다. example
저장소는 두 개의 명령(hello
와 outyet
)과 하나의 라이브러리(stringutil
)를 가집니다. image
저장소는 bmp
패키지와 몇몇 다른 것들을 가집니다.
작업 공간은 주로 많은 패키지와 명령을 가진 많은 소스 저장소를 가집니다. 대부분의 Go 프로그래머들은 모든 Go 소스와 의존성을 하나의 작업 공간에 보관합니다.
심볼릭 링크는 파일이나 디렉터리를 작업 공간에 링크하는 데 사용되면 안된다는 것을 알아두세요.
명령과 라이브러리들은 다른 종류의 소스 패키지에서 빌드됐습니다. 이부분은 이후에 다루게 됩니다.
GOPATH
환경 변수GOPATH
환경 변수는 작업 공간의 위치를 명시합니다. 기본적으로 여러분의 home 디렉터리 안에 go
라는 이름을 가진 디렉터리입니다. 즉, Unix에서는 $HOME/go
, Plan 9에서는 $home/go
, Windows에서는 %USERPROFILE%\go
(주로 C:\Users\YourName\go
)입니다.
다른 위치에서 작업하고자 한다면, 해당 디렉터리로 GOPATH
설정이 필요합니다. (또다른 공용 설치는 GOPATH=$HOME
으로 설정합니다.) GOPATH
Go 설치와 같은 디렉터리면 안된다는 점을 알아두세요.
go env GOPATH
명령은 현재 GOPATH
를 출력합니다. 환경 변수가 설정되지 않았다면 기본 위치를 출력합니다.
편의를 위해, 작업 공간의 bin
서브디렉터리를 PATH
에 추가합니다:
$ export PATH=$PATH:$(go env GOPATH)/bin
이 문서의 나머지 부분에서는 간결성을 위해 $(go env GOPATH)
대신 $GOPATH
를 사용합니다. GOPATH를 설정하지 않고 스크립트가 작성된 대로 동작하게 하려면, 명령들에서 $HOME/go로 대체하거나 다음을 실행합니다:
$ export GOPATH=$(go env GOPATH)
GOPATH 환경 변수에 대해 더 알아보려면, go help gopath
를 보세요.
커스텀 작업 공간 위치를 사용하려면, GOPATH
환경 변수 설정을 보세요.
*임포트 경로*는 패키지를 고유하게 식별하는 문자열입니다. 패키지의 임포트 경로는 작업 공간이나 (아래에서 설명할)원격 저장소 안에서 자신의 위치에 대응합니다.
"fmt"
와 "net/http"
과 같은 표준 라이브러리 패키지는 짧은 임포트 경로가 주어집니다. 여러분의 고유 패키지에 대해서는 미래에 추가될 표준 라이브러리나 외부 라이브러리와 충돌할 가능성이 없는 기본 경로를 선택해야 합니다.
코드를 소스 저장소 어딘가에 보관하면, 그 소스 저장소의 루트를 기본 경로로 사용하는 것이 좋습니다. 예를 들어, github.com/user
에 GitHub 계정을 가지고 있다면 이것이 기본 경로가 되는 것이 좋습니다.
여러분이 빌드할 수 있기 전에 원격 저장소에 코드를 게시할 필요는 없다는 것을 알아두세요. 언젠가 게시할 것 처럼 코드를 정리하는 것은 좋은 습관입니다. 표준 라이브러리와 더 큰 Go 생태계에 고유하기만 하다면, 실제로 어떤 임의의 경로 이름도 선택할 수 있습니다.
github.com/user
를 기본 경로로 사용합니다. 소스 코드를 보관할 디렉터리를 작업 공간 안에 만듭니다:
$ mkdir -p $GOPATH/src/github.com/user
간단한 프로그램을 컴파일하고 실행하기 위해, 먼저 패키지 경로를 선택하고 대응하는 패키지 디렉터리를 작업 공간 안에 생성합니다:
$ mkdir $GOPATH/src/github.com/user/hello
다음으로, 디렉터리 안에 hello.go
라는 이름으로 파일을 생성합니다. 파일은 다음 Go 코드를 갖습니다:
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
이제 go
도구로 프로그램을 빌드하고 설치할 수 있습니다:
$ go install github.com/user/hello
이 명령을 시스템 어느 곳에서든 실행할 수 있다는 점을 기억하세요. go
도구는 GOPATH
에 명시된 작업 공간 안에서 github.com/user/hello
패키지를 찾아서 소스 코드를 찾습니다.
또한 패키지 디렉터리에서 go install
을 실행하면 패키지 경로를 생략할 수 있습니다:
$ cd $GOPATH/src/github.com/user/hello
$ go install
이 명령은 실행 가능한 바이너리를 만들어 hello
명령을 빌드합니다. 그 다음 이 바이너리를 작업 공간의 bin
디렉터리에 hello
(또는, Windows의 경우 hello.exe
)로 설치합니다. 이 예제에서는 $GOPATH/bin/hello
, 즉 $HOME/go/bin/hello
가 될 것입니다.
go
도구는 오류가 발생했을 때만 출력합니다. 때문에 이러한 명령들이 아무런 출력도 내지 않는다면 성공적으로 실행된 것입니다.
이제 커맨드 라인에서 전체 경로를 입력하여 프로그램을 실행할 수 있습니다:
$ $GOPATH/bin/hello
Hello, world.
또는, PATH
에 $GOPATH/bin
을 추가했기 때문에 바이너리 이름만 입력합니다:
$ hello
Hello, world.
버전 관리 시스템을 사용중이라면, 지금이 저장소를 초기화할 좋은 때입니다. 파일을 추가하고, 변경 사항을 커밋합니다. 다시 말하지만, 이 단계는 선택사항입니다: Go 코드를 작성하기 위해 버전 관리를 사용할 필요는 없습니다.
$ cd $GOPATH/src/github.com/user/hello
$ git init
Initialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/
$ git add hello.go
$ git commit -m "initial commit"
[master (root-commit) 0b4507d] initial commit
1 file changed, 1 insertion(+)
create mode 100644 hello.go
코드를 원격 저장소에 푸시(push)하는 것은 독자 여러분의 몫으로 남겨두겠습니다.
라이브러리를 작성하고 hello
프로그램에서 사용해봅시다.
다시한번 말하지만, 첫 단계는 패키지 경로(여기서는 github.com/user/stringutil
)를 선택하고 패키지 디렉터리를 생성하는 것입니다:
$ mkdir $GOPATH/src/github.com/user/stringutil
다음으로, 디렉터리에 다음의 내용으로 reverse.go
라는 이름의 파일을 생성합니다.
// Package stringutil contains utility functions for working with strings.
package stringutil
// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
이제, go build
로 패키지가 컴파일되는지 확인합니다:
$ go build github.com/user/stringutil
또는 패키지의 소스 디렉터리에서 작업중이라면:
go build
출력은 나오지 않을 것입니다. 대신 컴파일된 패키지를 로컬 빌드 캐시에 저장합니다.
stringutil
패키지 빌드를 환인한 뒤에, 이를 사용하기 위해 ($GOPATH/src/github.com/user/hello
에 있는)원래의 hello.go
파일을 수정합니다:
package main
import (
"fmt"
"github.com/user/stringutil"
)
func main() {
fmt.Println(stringutil.Reverse("!oG ,olleH"))
}
hello
프로그램을 설치합니다:
$ go install github.com/user/hello
이 프로그램의 새 버전을 실행하여 반전된 메시지를 봅니다:
$ hello
Hello, Go!
위의 단계 이후에, 작업 공간은 다음과 같습니다:
bin/
hello # command executable
src/
github.com/user/
hello/
hello.go # command source
stringutil/
reverse.go # package source
Go 소스 파일의 첫 문장은 다음과 같아야 합니다:
package name
*name*은 임포트를 위한 패키지의 기본 이름입니다. (패키지 안의 모든 파일은 같은 *name*을 사용해야 합니다.)
Go의 관례는 패키지 이름은 임포트 경로의 마지막 요소라는 것입니다: crypto/rot13
으로 임포트된 패키지의 이름은 rot13
이어야 합니다.
패키지 이름이 하나의 바이너리에 링크되는 모든 패키지에서 유일해야 한다는 조건은 없습니다, 오직 임포트 경로(완전한 파일 이름)만 유일합니다.
Go의 이름 짓기 관례에 대해 더 알아보려면 Effective Go를 보세요.
Go는 go test
명령과 testing
패키지로 구성된 경량 테스트 프레임워크를 가지고 있습니다.
시그니처가 func (t *testing.T)
이면서 TestXXX
형태로 명명된 함수를 가지고 이름이 _test.go
로 끝나는 파일을 생성하여 테스트를 작성합니다. 테스트 프레임워크는 이러한 함수들을 각각 실행합니다. 만약 함수가 t.Error
또는 t.Fail
과 같은 실패 함수를 호출하면, 테스트는 실패한 것으로 간주됩니다.
다음 코드를 가진 $GOPATH/src/github.com/user/stringutil/reverse_test.go
파일을 생성하여 stringutil
패키지에 테스트를 추가합니다.
package stringutil
import "testing"
func TestReverse(t *testing.T) {
cases := []struct {
in, want string
} {
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := Reverse(c.in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
}
}
}
그 다음, go test
로 테스트를 실행합니다:
$ go test github.com/user/stringutil
ok github.com/user/stringutil 0.165s
늘 그렇듯, 패키지 디렉터리에서 go
도구를 실행중이라면, 패키지 경로를 생략할 수 있습니다:
$ go test
ok github.com/user/stringutil 0.165s
더 자세한 내용은 go help test
를 실행해보고 testing 패키지 문서를 보세요.
임포트 경로는 Git이나 Mercurial과 같은 버전 관리 시스템을 사용하여 패키지 소스 코드를 얻는 방법을 기술합니다. go
도구는 원격 저장소에서 패키지를 자동으로 가져오는 데에 이 특성을 사용합니다. 예를 들어, 이 문서에 기술된 예시는 GitHub github.com/golang/example
에 호스트된 Git 저장소에도 보관되어 있습니다. 만약 패키지의 임포트 경로에 저장소 URL을 포함하면, go get
이 이를 자동으로 가져와서 빌드하고 설치할 것입니다:
$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!
만약 명시된 패키지가 작업 공간에 존재하지 않으면, go get
이 GOPATH
에 명시된 첫 번째 작업 공간 안에 이를 위치시킬 것입니다. (만약 패키지가 이미 존재하면, go get
은 원격 저장소에서 가져오는 과정을 건너뛰고 go install
과 동일하게 동작합니다.)
go get
명령 이후에, 이제 작업 공간 디렉터리 트리는 다음과 같습니다:
bin/
hello # command executable
src/
github.com/golang/example/
.git/ # Git repository metadata
hello/
hello.go # command source
stringutil/
reverse.go # package source
reverse_test.go # test source
github.com/user/
hello/
hello.go # command source
stringutil/
reverse.go # package source
reverse_test.go # test source
GitHub에서 호스트되는 hello
명령은 같은 저장소 안의 stringutil
패키지에 의존합니다. hello.go
파일의 임포트는 같은 임포트 경로 관례를 사용합니다, 따라서 go get
명령도 의존 패키지를 위치시키고 설치할 수 있습니다.
import "github.com/golang/example/stringutil"
이 관례는 Go 패키지를 다른 사람들이 사용할 수 있도록 만드는 가장 쉬운 방법입니다. Go Wiki와 godoc.org가 외부 Go 프로젝트 목록을 제공합니다.
go
도구를 이용한 원격 저장소 사용에 대해 더 많은 정보는 go help importpath
를 보세요.
golang-announce 메일링 리스트를 구독해서 새로운 Go 안정 버전이 릴리즈됐을 때 알림을 받으세요.
깔끔하고 자연스러운 Go 코드를 작성하는 팁은 Effective Go를 보세요.
언어를 배우려면 A Tour of Go를 보세요.
Go 언어와 라이브러리와 도구들에 대해 더 깊이 다룬 글들은 documentation page를 방문하세요.
실시간 도움은 Freenode IRC 서버의 #go-nuts
에서 gopher들에게 물어보세요.
Go 언어의 논의를 위한 공식 메일링 리스트는 Go Nuts입니다.
버그는 Go 이슈 트래커를 사용해서 보고해주세요.