[Go] 10. 패키지

2024. 1. 20. 19:04Go

반응형

package는 Go에서 코드를 묶는 가장 큰 단위입니다

구조체로 데이터를 묶고, 함수로 코드를 묶었다면
패키지는 함수와 구조체 그리고 그외의 코드를 묶습니다.

main패키지는 프로그램의 시작점인 main()함수를 포함한 패키지 입니다. (프로그램의 시작점이기 때문에 필수 요소입니다)

하나의 프로그램은 main패키지 하나와 0개 이상의 외부 패키지로 구성됩니다.

패키지명은 아래와 같은 규칙으로 만드는 것을 권장합니다.

  • 최대한 간소하게
  • 소문자만을 이용하여 만들기

GoLang Standard library 에서 유용한 패키지를 학습하고, 표준 패키지에서 제공하고 있는 기능이라면 활용하여 서비스를 구현하는 것이 좋습니다.

Awesome Go 에서도 많이 사용되는 패키지를 참고할 수 있습니다.


1. 패키지 import

Go에서 import된 패키지를 찾는 방법은 아래와 같습니다.

  1. Go설치 경로로부터 Go 기본제공 패키지(fmt 등...)를 찾고
  2. 외부 repository(GitHub 등...)에 저장된 패키지의 경우, 다운받아서 GOPATH/pkg 에 설치합니다.
    1. go env GOPATH 명령어로 GOPATH를 조회할 수 있습니다.
  3. 현재 모듈 하위에 위치한 패키지를 조회합니다.

import할 패키지가 하나라면 큰따옴표로 패키지명을 감싸서 아래와 같이 작성하면 되고

import "fmt"

여러개면 아래와 같이 소괄호로 감싸서 import합니다
경로가 있을 경우에는 경로를 그대로 작성하고, 맨마지막 디렉토리명을 이용하여 메서드를 이용합니다.

아래는 math/rand 패키지를 이용하여 0이상 10미만의 랜덤수 10개를 출력하는 코드입니다.

package main  

import (  
  "fmt"  
  "math/rand"
)  

func main() {  
  for i := 0; i < 10; i++ {  
   fmt.Print(rand.Intn(10), " ")  
  }  
}

만약, 패키지 명이 동일한 패키지를 import해야한다면, 패키지명 앞에 별명을 붙여주면 됩니다.

import (
	"text/template"
	htemplate "html/template"
)

사용하지 않는 패키지명을 import할 경우, 에러가 납니다.
사용하지는 않지만 부가효과를 이용하기 위해 import가 필요한 경우에는 패키지명 앞에 _를 붙여주면 됩니다.

부가효과란 패키지가 초기화되면서 실행되는 코드에 따른 효과를 의미합니다.

import (
	_ "github.com/mattn/go-sqlite3"
)

2. Go모듈

Go 1.16 이상의 버전에서는 모든 Go코드는 Go모듈 아래에 있어야 합니다.

이전 버전의 경우, Go모듈을 만들지 않은 Go코드는 GOPATH/src 아래에 위치시켜야 했습니다

go build 하기 위해서는 Go모듈 루트 폴더에 go.mod 파일이 반드시 있어야 합니다.

go.mod 파일은 Go 버전, 필요한 외부 패키지 등이 명시된 파일입니다

Go모듈을 만드는 방법은 아래의 명령을 통해 go.mod 파일을 생성하는 것입니다.

go mod init 패키지명

go.mod 파일이 생성되면 go build 명령으로 빌드가 가능해지고, 빌드를 하면 Go 실행파일이 생성됩니다.


2.1. 모듈 활용 실습

goproject 프로젝트 내에서 usepkg 디렉토리를 만든 후, 그 디렉토리로 이동하여

mkdir usepkg
cd usepkg

아래의 명령어를 이용하여 usepkg디렉토리가 모듈 작동되도록 합니다.

go mod init goproject/usepkg

그러면 아래와 같은 내용을 담고 있는 go.mod파일이 생성됩니다.

module goproject/usepkg

go 1.21.5

2.1.1. 모듈 내 패키지 만들기

usepkg 내에 custompkg디렉토리를 만들고, custompkg.go를 만듭니다.

mkdir custompkg
cd custompkg
vim custompkg.go
package custompkg  

import "fmt"  

func PrintLine() {  
  fmt.Println("-----------")  
}

2.1.2. 모듈 내 패키지 및 외부 repository 패키지 활용

다시 상위 디렉토리인 usepkg로 이동하여, usepkg.go를 생성하고 모듈내에 있는 패키지를 활용해봅니다.

cd ..
touch usepkg.go

조금 전에 생성한 모듈과 ("goproject/usepkg/custompkg")
github에 있는 외부 repository 패키지를 import하여 함수를 사용해보았습니다.

package main  

import (  
  "fmt"  
  "github.com/guptarohit/asciigraph"  
  "goproject/usepkg/custompkg"
)  

func main() {  
  custompkg.PrintLine()  
  data := []float64{3, 4, 5, 8, 10, 5, 2}  
  graph := asciigraph.Plot(data)  
  fmt.Println(graph)  
}

go mod tidy 명령어를 이용하여 필요한 외부 패키지를 다운받습니다.

go mod tidy

그러면 외부 패키지가 다운로드 받아지고, go.mod 파일에 맨 아래줄이 추가된 것을 확인할 수 있으며, go.sum 파일이 생성됩니다.

module goproject/usepkg  

go 1.21.5  

require github.com/guptarohit/asciigraph v0.5.6

go.sum 파일에도 패키지의 버전정보가 기입되어있는데, 패키지의 위조 여부를 검사하기 위한 checksum 결과를 답고 있습니다.

github.com/guptarohit/asciigraph v0.5.6 h1:0tra3HEhfdj1sP/9IedrCpfSiXYTtHdCgBhBL09Yx6E=  
github.com/guptarohit/asciigraph v0.5.6/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=

필요한 패키지를 모두 다운받았으니, 이제 빌드 후 프로그램을 실행할 수 있습니다.

go build
./usepkg
-----------
 10.00 ┤   ╭╮
  9.00 ┤   ││
  8.00 ┤  ╭╯│
  7.00 ┤  │ │
  6.00 ┤  │ │
  5.00 ┤ ╭╯ ╰╮
  4.00 ┤╭╯   │
  3.00 ┼╯    │
  2.00 ┤     ╰

다운받은 외부 패키지 모듈은 GOPATH/pkg/mod 에 설치됩니다.

MacOS의 경우 ~/go 하위에 설치됩니다.



이미 다운받은 패키지를 다른 모듈에서 활용할 때에는, 다운로드하지 않고 기존에 다운받았던 모듈을 사용합니다.


3. 패키지 외부 공개

ch16디렉토리 하위에 모듈로 이용할 ex16.2 디렉토리를 생성한 후, 그 디렉토리로 이동한 후, go mod init 명령어를 실행합니다.

cd ch16
mkdir ex16.2
cd ex16.2
go mod init ch16/ex16.2
mkdir publicpkg
cd publicpkg
vim publicpkg.go

publicpkg.go 파일에 변수와 상수, 구조체, 함수 등을 공개형과 비공개형을 정의해봅니다.

맨 첫번째 문자를 대문자로 설정할 경우 공개형태가 되고, 소문자로 설정할 경우 비공개형태가 됩니다.

package publicpkg  

import "fmt"  

const (  
  PI = 3.1415  
  pi = 3.14  
)  

var ScreenSize = 1080  
var screenHeight int  

func PublicFunc() {  
  const MyConst = 100  
  fmt.Println("PublicFunc 는 공개함수입니다!", MyConst)  
}  

func privateFunc() {  
  fmt.Println("privateFunc 는 비공개함수입니다!")  
}  

type MyInt int  
type myString string  

type MyStruct struct {  
  Age  int  
  Name string  
}  

func (m MyStruct) PublicMethod() {  
  fmt.Println("MyStruct 에 들어있는 공개 메서드")  
}  

func (m MyStruct) privateMethod() {  
  fmt.Println("MyStruct 에 들어있는 비공개 메서드")  
}  

type myPrivateStruct struct {  
  Age  int  
  Name string  
}  

func (m myPrivateStruct) PrivateMethod() {  
  fmt.Println("myPrivateStruct 에 들어있는 비공개 메서드")  
}

상위 디렉토리로 이동한 후, ex16.2.go 파일을 생성하고, 조금 전에 정의한 공개변수/구조체/함수를 사용해봅시다.

package main  

import (  
  "ch16/ex16.2/publicpkg"  
  "fmt")  

func main() {  
  fmt.Printf("PI: %v, ScreenSize: %v\n", publicpkg.PI, publicpkg.ScreenSize)  
  publicpkg.PublicFunc()  

  var myInt publicpkg.MyInt = 10  
  fmt.Println("myInt:", myInt)  

  myStruct := publicpkg.MyStruct{Name: "jini"}  
  fmt.Println(myStruct)  
  myStruct.PublicMethod()  
}
PI:  3.1415
PublicFunc 는 공개함수입니다! 100
myInt: 10
{0 jini}
MyStruct 에 들어있는 공개 메서드

publicpkg 모듈내에서 공개형만 접근가능합니다!


4. 패키지 초기화

패키지를 import 했을 때, 아래의 동작 과정을 거칩니다.

  1. 컴파일러가 패키지 내의 전역변수를 초기화
  2. 패키지에 init()함수가 있을 경우, init()함수를 호출하여 패키지를 초기화함
    1. init() 함수는 반드시 입력 매개변수와 반환값이 없는 함수여야 합니다.

go에서 어떤 패키지를 사용하지는 않지만, 패키지에 정의된 패키지 초기함수인 init()함수의 기능을 원한다면, 아래와 같이 _ 을 이용하여 임포트하면 됩니다.

Go에서 import하였으나, 사용하지 않을 경우 에러가 발생되기 때문에

import (
	_ "github.com/mattn/go-sqlite3"
)

ex16.3 모듈을 만든 후,

mkdir ex16.3
cd ex16.3
go mod init ch16/ex16.3
mkdir exinit
vim exinit.go

패키지 초기화에 대해 알아보기 위한 예제를 작성해봅니다.

package exinit  

import "fmt"  

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

func init() {  
  d++  
  fmt.Println("init 함수 실행! d: ", d)  
}  

func f() int {  
  d++  
  fmt.Println("f() 함수 실행! d: ", d)  
  return d  
}  

func PrintD() {  
  fmt.Println("d: ", d)  
}

import 함수에서 exinit 패키지를 import할 때,
exinit 패키지 내에 정의된 변수의 초기화와 init()함수가 실행됩니다.
그 후에, main함수가 실행을 시작합니다.

package main  

import (  
  "ch16/ex16.3/exinit"  
  "fmt")  

func main() {  
  fmt.Println("------")  
  exinit.PrintD()  
}
f() 함수 실행! d:  4
f() 함수 실행! d:  5
init 함수 실행! d:  6
------
d:  6
728x90
반응형

'Go' 카테고리의 다른 글

[Go] 13. 인터페이스  (0) 2024.01.21
[Go] 12. 메서드  (0) 2024.01.21
[Go] 09. 문자열  (0) 2024.01.18
[Go] 08. 포인터  (0) 2024.01.18
[Go] 07. 배열, 구조체  (1) 2024.01.17