Skip to content

Go 코드를 작성하는 방법

Donghyun Yun edited this page Feb 9, 2017 · 9 revisions

https://golang.org/doc/code.html 문서의 한국어 번역 문서 입니다.

소개

이 문서는 간단한 Go 패키지의 개발과 Go 패키지와 Command를 가져와 빌드하고, 설치하는 표준적인 방법 인 go tool 을 소개합니다.

go tool을 사용하려면 코드를 특정한 방식으로 구조를 잡아야합니다. 이 문서를 주의 깊게 읽으십시오. Go를 준비하고 실행하는 가장 간단한 방법을 설명합니다.

비슷한 설명이 screencast로 제공됩니다.

코드 구조

개요

  • Go 프로그래머들은 전형적으로 모든 Go 코드를 단일 workspace에서 관리 합니다.
  • 하나의 workspace에는 다수의 버전 관리 저장소(예: Git으로 관리되는)들을 포함합니다.
  • 각 저장소는 하나 이상의 패키지들이 있습니다.
  • 각 패키지는 단일 디렉토리 내에 하나 이상의 Go 소스 파일들로 구성됩니다.
  • 패키지의 디렉토리 경로 자체가 import 경로를 결정 합니다.

이는 프로젝트마다 별도의 workspace 가 있고, 이 workspace가 버전 관리 저장소에 밀접하게 연결된 다른 프로그래밍 환경들과는 다릅니다.

Workspace

Workspace는 세 개의 하위 디렉토리가 있는 디렉토리 계층 구조입니다.

  • src 에는 Go 소스 파일들이 있으며,
  • pkg 에는 패키지 객체들이 있으며,
  • bin 에는 실행 가능한 커멘드들이 들어 있습니다.

go tool은 소스 패키지를 빌드하고 결과 바이너리들을 pkgbin 디렉토리에 설치합니다.

src 서브 디렉토리는 일반적으로 하나 이상의 소스 패키지의 개발을 관리하는 여러 버전 관리 저장소(Git 또는 Mercurial과 같은)들을 포함합니다.

실제로 작업 공간이 어떻게 보이는지 알려주기 위해 다음과 같은 예가 있습니다:

bin/
    hello                      # command 실행 프로그램
    outyet                     # command 실행 프로그램
pkg/
    linux_amd64/
        github.com/golang/example/
            stringutil.a       # 패키지 객체
src/
    github.com/golang/example/
        .git/                      # Git 저장소 메타 데이터
    hello/
        hello.go               # command 소스
    outyet/
        main.go                # command 소스
        main_test.go           # 테스트 소스
    stringutil/
        reverse.go             # 패키지 소스
        reverse_test.go        # 테스트 소스
    golang.org/x/image/
        .git/                      # Git 저장소 메타 데이터
    bmp/
        reader.go              # 패키지 소스
        writer.go              # 패키지 소스
    ... (많은 저장소와 패키지들이 생략 됨) ...

위의 트리 구조는 두 개의 저장소(exampleimage)가 포함 된 workspace를 보여줍니다. example 저장소는 두 개의 command(hellooutyet)와 하나의 라이브러리(stringutil)를 포함합니다. image 저장소는 bmp 패키지와 몇몇 다른 것들을 포함합니다.

일반적인 workspace에는 많은 패키지와 command들이 들어있는 많은 소스 저장소가 있습니다. 대부분의 Go 프로그래머들은 모든 Go 소스 코드와 필요한 라이브러리들을 단일 workspace에서 관리합니다.

Command 및 라이브러리는 다양한 종류의 소스 패키지로부터 빌드됩니다. 우리는 나중에 그 구별 방식(패키지 이름)을 이야기 할 것입니다.

GOPATH 환경 변수

GOPATH 환경 변수는 workspace 의 위치를 ​​지정합니다. 아마도 Go 코드를 개발할 때 설정해야 할 유일한 환경 변수 일 것입니다.

먼저, workspace 디렉토리를 만들고 아래처럼 GOPATH를 설정하십시오. workspace는 원하는 위치 어디든 가능하지만, 이 문서에서는 $HOME/work 를 사용합니다. 이 경로는 Go 배포판이 설치된 경로와 같아서는 안됩니다.(또 다른 일반적인 설정은 GOPATH=$HOME로 지정하는 방식이 있습니다.)

$ mkdir $HOME/work
$ export GOPATH=$HOME/work

편의상 workspace의 bin 하위 디렉토리를 PATH에 추가:

$ export PATH=$PATH:$GOPATH/bin

GOPATH 환경 변수 설정에 대한 자세한 설명은 go help gopath을 참조하십시오.

Import 경로

import 경로는 패키지를 고유하게 식별하는 문자열입니다. 패키지의 import 경로는 workspace 또는 원격 저장소 내에서의 위치를 따릅니다(아래 설명 참조).

표준 라이브러리의 패키지에는 "fmt" 및 "net/http" 와 같은 짧은 import 경로가 지원됩니다. 직접 만든 자신의 패키지의 경우, 표준 라이브러리 나 다른 외부 라이브러리와 추후 충돌날 가능성이 없는 베이스 경로를 선택해야합니다.

코드를 어딘가에 소스 저장소에 보관하면 해당 소스 저장소의 root를 기본 경로로 사용해야합니다. 예를 들어, github.com/user GitHub 계정을 가지고 있다면 이것을 베이스 경로로 써야합니다.

코드를 빌드하기 전에 원격 저장소에 코드를 배포 할 필요는 없습니다. 언젠가 배포 할 것처럼 코드를 구성하는 것은 단지 좋은 습관일 뿐입니다. 실질적으로는 표준 라이브러리와 커다란 Go 생태계에서 고유하기만 하다면, 어떤 임의의 경로 이름도 선택할 수 있습니다.

여기서는 github.com/user 를 기본 경로로 사용합니다. 소스 코드를 보관할 workspace 내부에 디렉토리를 만듭니다:

$ mkdir -p $GOPATH/src/github.com/user

여러분의 첫 번째 프로그램

간단한 프로그램을 컴파일하고 실행하기 위해, 먼저 패키지 경로(github.com/user/hello 사용)를 선택하고, workspace 내에 해당 패키지 디렉토리를 만듭니다.

$ mkdir $GOPATH/src/github.com/user/hello

다음으로, 아래의 Go 코드가 포함 된 hello.go 라는 파일을 해당 디랙토리 내에 작성하십시오.

package main

import "fmt"

func main() {
    fmt.Printf("Hello, world.\n")
}

이제 go tool 을 이용해 빌드하고 설치할 수 있습니다.

$ go install github.com/user/hello

시스템의 어느 곳에서나 해당 프로그램(command)를 실행할 수 있습니다. go tool은 GOPATH로 지정된 workspace에서 github.com/user/hello 패키지를 검색하여 소스 코드를 찾습니다.

package 디렉토리에서 go install을 실행하면 패키지 경로는 생략 할 수 있습니다.

$ cd $GOPATH/src/github.com/user/hello
$ go install

이 명령은 는 hello command를 빌드하여 실행 바이너리를 생성합니다. 그런 다음 이 바이너리를 workspace 의 bin 디렉토리에 hello(Windows 환경에서는 hello.exe)로 설치합니다. 우리의 예제에서는 $GOPATH/bin/hello,즉 $HOME/work/bin/hello 입니다.

go tool은 오류가 발생할 때만 아웃풋이 출력됨으로,이 명령들이 아무런 출력을 하지 않으면 성공적으로 수행된 것 입니다.

이제 커멘드 라인에서 전체 경로를 입력하여 프로그램을 실행할 수 있습니다.

$ $GOPATH/bin/hello
Hello, world.

또는 $GOPATH/binPATH 에 추가했었다면, 바이너리 이름만으로도 가능합니다.

$ 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

코드를 원격 저장소로 푸시하는 것은 여러분의 연습 과제로 남겨 둡니다.

여러분의 첫 번째 라이브러리

라이브러리를 작성하고 hello 프로그램에서 사용해봅시다.

첫 번째 단계는 패키지 경로(github.com/user/stringutil을 사용)를 선택하고 패키지 디렉토리를 만드는 것입니다.

$ mkdir $GOPATH/src/github.com/user/stringutil

그런 다음, 아래처럼 해당 디렉토리에 reverse.go 라는 파일을 작성하십시오.

// 패키지 stringutil 은 문자열 작업을 위한 유틸리티 함수들을 포함하고 있음
package stringutil

// Reverse 는 인자 문자열을 rune-wise 방식으로 왼쪽에서 오른쪽으로 반전하여 리턴합니다.
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

이는 목적 파일을 생성하지는 않습니다. 목적 파일을 생성하려면 go install 을 사용하여 패키지 오브젝트를 workspace 의 pkg 디렉토리에 설치할 수 있습니다.

stringutil 패키지가 빌드되는지 확인한 후, 원래의 hello.go($GOPATH/src/github.com/user/hello)를 수정하여 이 라이브러리를 사용할 수 있습니다.

package main

import (
    "fmt"

    "github.com/user/stringutil"
)

func main() {
    fmt.Printf(stringutil.Reverse("!oG ,olleH"))
}

go tool이 패키지 또는 바이너리를 설치할 때마다 종속성이 있는 패키지도 설치합니다. 그래서 hello 프로그램을 설치할 때는

$ go install github.com/user/hello

stringutil 패키지도 자동으로 설치됩니다.

새 버전의 프로그램을 실행하면 새로운 반전된 메시지를 볼 수 있습니다.

$ hello
Hello, Go!

위의 단계를 수행 한 후, workspace 는 다음과 같은 상태가 되어야합니다.

bin/
   hello                 # command 실행파일
pkg/
    linux_amd64/          # 여러분의 OS와 아키텍쳐에 따라 다름
        github.com/user/
            stringutil.a  # package 오브젝트
src/
    github.com/user/
        hello/
            hello.go      # command 소스
        stringutil/
            reverse.go    # package 소스 

go installpkg/linux_amd64 디렉토리 내에 소스 디렉토리와 대응하는 stringutil.a 오프젝트를 둡니다. 이렇게 하면 이후에 go tool을 호출 할 때 패키지 오브젝트를 찾을 수 있고 패키지를 불필요하게 다시 컴파일하지 않아도 됩니다. linux_amd64 부분은 크로스-컴파일을 돕기 위한 부분으로 시스템의 운영 체제와 아키텍처를 반영합니다.

Go 실행 파일은 정적으로 링크됩니다: 패키지 오브젝트는 Go 프로그램을 실행하는 데 필요하지 않습니다.

패키지 이름

Go 소스 파일의 첫 번째 선언문은 다음과 같아야합니다.

package name

여기서 name 은 import 에 대한 패키지의 기본 이름입니다. (하나의 패키지의 모든 파일은 동일한 name 사용해야합니다.)

Go의 관례는 패키지 이름이 import 경로의 마지막 요소입니다: "crypto/rot13" 으로 import 된 패키지의 이름은 rot13 이어야합니다.

실행 가능한 command들은 항상 package main을 사용해야 합니다.

패키지 이름은 단일 바이너리에 링크 된 모든 패키지들에서 고유할 필요는 없지만, import 경로(전체 파일 이름)는 고유해야 합니다.

Go의 명명 규칙에 대한 자세한 내용은 Effective Go 문서를 참조하십시오.

테스트

Go에는 go test 명령과 testing 패키지로 구성된 경량 테스트 프레임워크가 있습니다.

_test.go로 끝나는 이름의 파일을 작성하여 테스트를 작성합니다. _test.go 파일에는 타입이 func (t *testing.T)TestXXX 이름의 함수들이 들어있습니다. 테스트 프레임 워크는 이러한 각 함수를 실행합니다. 만약 함수가 t.Error 또는 t.Fail 과 같은 실패 함수를 호출하면, 테스트는 실패한 것으로 간주됩니다.

다음 Go 코드를 포함하는 $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 tool를 실행하는 경우 패키지 경로를 생략 할 수 있습니다:

$ go test
ok    github.com/user/stringutil 0.165s

자세한 내용은 go help test 를 실행하거나 testing 패키지 문서를 참조하십시오.

원격 패키지들

import 경로는 Git 또는 Mercurial과 같은 버전 관리 시스템을 사용하여 패키지 소스 코드를 얻는 방법을 명세 할 수 있습니다. go tool은 이 정보를 사용하여 원격 저장소에서 패키지를 자동으로 가져옵니다. 예를 들어,이 문서에서 설명하는 예제는 GitHub github.com/golang/example 에서 호스팅되는 Git 저장소에도 보관됩니다. 저장소 URL을 패키지의 import 경로에 포함 시키면 go get 은 자동으로 가져와 빌드하고 설치합니다.

$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!

지정된 패키지가 workspace 에 없으면, go get 명령은 GOPATH 의 첫 번째 workspace 에 패키지를 설치합니다.(패키지가 이미 존재하면, go get 은 원격에서 가져오기를 생략하고, go install 과 동일하게 동작합니다.)

위의 go get 명령을 실행하면, workspace 디렉토리 구조가 아래와 같이 보여야합니다:

bin/
    hello                           # command 실행파일
pkg/
    linux_amd64/
        github.com/golang/example/
            stringutil.a            # package 오브젝트
        github.com/user/
            stringutil.a            # package 오브젝트
src/
    github.com/golang/example/
    .git/                       # Git 저장소 메타정보
        hello/
            hello.go                # command 소스
        stringutil/
            reverse.go              # package 소스
            reverse_test.go         # test 소스
    github.com/user/
        hello/
            hello.go                # command 소스
        stringutil/
            reverse.go              # package 소스
            reverse_test.go         # test 소스

GitHub에서 호스팅되는 hello command는 동일한 저장소 내의 stringutil 패키지를 참조합니다. hello.go 파일의 import 는 동일한 import 경로 규칙을 사용하므로, go get 명령은 종속 패키지를 찾아서 설치할 수 있습니다.

import "github.com/golang/example/stringutil"

이 규칙은 Go 패키지를 다른 사람들이 사용할 수 있게 만드는 가장 쉬운 방법입니다. Go Wikigodoc.org 는 외부 Go 프로젝트들의 목록을 제공합니다.

go tool을 이용해 원격 저장소를 사용하는 방법에 대한 자세한 내용은 go help importpath 참고하십시오.

이후 볼 것들

golang-announce 메일링 리스트를 구독 하면 새로운 안정 버전의 Go가 릴리스 될 때 알림을 받을 수 있습니다.

명확하고 관용적인 Go 코드 작성에 대한 팁은 Effective Go 를 참조하십시오.

언어 특성을 배우려면 Go Tour 를 보십시오.

Go 언어와 라이브러리 및 도구에 대한 심도있는 기사들을 보려면 documentation 페이지 를 방문하십시오.

도움 받기

실시간 도움을 얻으려면, Freenode IRC 서버에있는 #go-nuts 에서 도움이 되는 고퍼들에게 도움을 요청하십시오.

Go 언어 토론을 위한 공식 메일링 리스트는 Go Nuts 입니다.

Go 이슈 트래커를 사용해 버그를 보고하십시오.