본문으로 바로가기

Go 패키지 & Go 모듈

category Programming Language/🐿️ Go (Golang) 2021. 5. 13. 08:32

어디서 패키지들을 찾나요?

golang.org : golang.org/pkg/ language, stdlib
godoc.org : stdlib, third-party packages

다른 사람들이 많이 사용하는 pkg 모음 : github.com/avelino/awesome-go
쉽게 말해 패키지 찾으려면 godoc, 일반 문서를 보려면 golang.

 

동일한 이름의 패키지를 구별하기 위해 aliasing하기

같은 이름의 패키지가 있다면 아래와 같이 별칭을 붙여줄 수 있습니다.

package main

import (
	htemplate "html/template" // [alias] "템플릿 이름" 꼴로 별칭
	"text/template"
)

func main() {
	template.New("darren").Parse(`{{define "T"}}Hello`)
	htemplate.New("darren").Parse(`{{define "T"}}Hello`)
}

 

특수한 별칭으로, _(underbar) 를 붙여주면, 사용하지 않는 패키지도 정의할 수 있습니다.

사용하지 않는데 왜 정의하냐구요? 패키지 초기화에서 실행되는 코드들의 도움이 필요한 경우에 사용합니다.

 

외부 패키지?

go build할 때는 패키지를 찾아서 포함한 다음에 exec를 만들어냅니다.

stdlib는 Go의 설치 경로에서 찾습니다. 저 같은 경우에는 /Users/%USERPROFILE%/go (~/go, GOPATH)

외부 저장소에 저장된 패키지의 경우 외부 저장소에 다운로드 받아서 Go의 설치 경로의 pkg 폴더 내부에 별도 설치합니다.

GOPATH/pkg/mod에 가보니 아래와 같이 외부 패키지들이 저장되어 있는 것을 확인해볼 수 있습니다.

따라서 한 번 로컬에 다운로드 받았다면, 다른 모듈에서 사용하더라도 별도로 다운로드 받을 필요 없습니다.

node_module 지옥에서 해방...

 

 

 

 

Go Module + 커스텀 패키지와 외부 패키지 사용 플로우

Go 모듈은 Go 패키지를 모아서 작성하는 프로젝트 덩어리를 말합니다.

모듈을 구분하는 방법은 go build 명령어를 통해 Go 모듈 루트 폴더에 go.mod 파일이 있어야 합니다.

즉, Module을 구별하는 단위는 go.mod 파일 단위입니다.

 

1. 모듈 생성 = 프로젝트 생성

 

결과로 go.mod 파일이 생성됩니다.

go mod init [원하는 이름]
// go mod init pkg-example

 

2. 커스텀 pkg 생성을 위해 폴더 생성

 

폴더를 생성하고, 패키지를 정의합니다. 

그리고 저는 node를 하던 사람이라서 그런지 패키지의 추출 되는 지점을 index.go로 이름지었는데,

패키지 이름으로 짓는 분들도 계시더라구요?

 

아래 커스텀 패키지를 작성할때 주의할 점은,

패키지 외부에서 접근 가능하게 하고 싶다면 구조체, 함수등의 이름이 '대문자로 시작해야'한다는 것입니다.

이는 struct, func, const, var, 별칭 type, 메서드

package custompkg

import "fmt"

const (
	PI = 3.14;
	pi = 3.14; // 외부 접근 불가
)

type Person struct {
	Name string
	age int // 외부 접근 불가
}

func PrintCustom() {
	fmt.Println("hello I'm from custom pkg")
}
package main

import (
	"fmt"
	"pkg-example/custompkg"
)

func main() {
	fmt.Println("hello")
	custompkg.PrintCustom()
	fmt.Println(custompkg.PI)

	me := custompkg.Person{Name: "darren"} // age 접근 불가
	fmt.Println(me) // {darren 0}
	fmt.Println(me.Name)
}

 

3. 외부 패키지 사용해보기

 

github.com/guptarohit/asciigraph 이 녀석을 사용해보도록하겠습니다.

우선 해당 모듈에 패키지를 다운로드 받기 위해 go get 명령어를 입력합니다.

그렇다면, 외부 패키지의 위조 검사한 체크섬 결과가 담긴 go.sum 파일이 생기게 됩니다.

go get github.com/guptarohit/asciigraph

 

만약 모듈에 있는 패키지를 모듈에 다시 다운로드 받는 경우에는 go mod tidy를 입력합니다.

 

최종적으론 아래와 같은 코드가 되었습니다.

package main

import (
	"fmt"
	"pkg-example/custompkg"

	"github.com/guptarohit/asciigraph"
)

func main() {
	fmt.Println("hello")
	custompkg.PrintCustom()

	data := []float64{3, 4, 9, 6, 2, 4, 5, 8, 5, 10, 2, 7, 2, 5, 6}
	graph := asciigraph.Plot(data)
	fmt.Println(graph)

}

 

 

4. 패키지 초기화

앞서서 패키지를 import 하는데, 초기화 코드만 필요한 경우 _(underbar)를 별칭으로 사용한다고 하였다.

이게 무슨 말이냐면, 아래와 같은 custom pkg가 있다고 가정해보자.

 

아래 코드에서 init()은 패키지가 임포트 된 순간 모든 전역 변수를 초기화한 후 작동합니다.

그러니까, a, b, c, d가 모두 초기화된 후에 init 함수가 발동한다는 말입니다.

* init은 인자도 없고 반환값도 없는 함수여야 합니다.

 

아래 코드를 보면, 전역 변수 a, b, c, d가 초기화 되려면 함수 f()의 실행 결과가 필요합니다.

코드를 읽어보고 실행 결과를 예측해봅시다.

package custompkg

import "fmt"

var (
	a = c + b
	b = f()
	c = f()
	d = 3
)

func init() {
	fmt.Println(a, b, c, d)
	fmt.Println("init!", d)
	d++
	fmt.Println("end init!", d)
}

func f() int {
	d++
	fmt.Printf("d is %d\n", d)
	return d
}

func PrintAll() {
	fmt.Println(a, b, c, d)
}

 

따라서 아래와 같은 순서로 출력됩니다.

 

d is 4 (c 정의)
d is 5 (b 정의)
9 4 5 5 (이제서야 init 함수 발동)
init! 5
end init! 6

 

어쨌거나 이런 init만 필요한 경우에 언더바를 별칭으로 사용합니다.


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체