본문으로 건너뛰기

패키지 시스템 — Go 코드 구성의 기본

Go의 모든 코드는 패키지(package) 단위로 구성됩니다. 패키지는 관련된 기능을 하나로 묶는 Go의 기본 코드 구조 단위입니다.

패키지 선언과 임포트

package main // 패키지 선언 — 모든 .go 파일의 첫 줄

import (
"fmt" // 표준 라이브러리
"math/rand" // 서브패키지
"os"

"github.com/gin-gonic/gin" // 외부 패키지 (모듈 필요)
)

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

패키지 이름 규칙:

  • 소문자만 사용
  • 짧고 명확하게 (가능하면 한 단어)
  • 디렉터리 이름과 일치 권장 (예외: main, _test)
  • 복수형이나 공통 접두어 피하기

공개(Exported) vs 비공개(Unexported)

Go는 이름의 첫 글자 대소문자 로 공개/비공개를 결정합니다.

package geometry

import "math"

// ✅ 공개 — 다른 패키지에서 접근 가능
type Circle struct {
Radius float64 // 공개 필드
color string // 비공개 필드 (같은 패키지에서만)
}

// ✅ 공개 함수
func NewCircle(radius float64) *Circle {
return &Circle{
Radius: radius,
color: "red", // 비공개 필드는 같은 패키지에서만 설정 가능
}
}

// ✅ 공개 메서드
func (c *Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}

// ❌ 비공개 메서드 — 같은 패키지에서만 사용
func (c *Circle) validate() bool {
return c.Radius > 0
}

// 공개 상수
const Pi = 3.14159

// 비공개 상수
const maxRadius = 1000.0

사용 예:

package main

import (
"fmt"
"myproject/geometry"
)

func main() {
c := geometry.NewCircle(5.0)
fmt.Println(c.Area()) // ✅ 공개 메서드 접근 가능
fmt.Println(c.Radius) // ✅ 공개 필드 접근 가능
// fmt.Println(c.color) // ❌ 컴파일 에러
// c.validate() // ❌ 컴파일 에러
}

init 함수 — 패키지 초기화

init() 함수는 패키지가 처음 로드될 때 자동으로 실행됩니다.

package database

import (
"fmt"
"log"
)

var (
connectionPool *Pool
maxConnections = 10
)

// init 함수: 패키지 로드 시 자동 실행
func init() {
fmt.Println("database 패키지 초기화 중...")
var err error
connectionPool, err = newPool(maxConnections)
if err != nil {
log.Fatalf("DB 풀 초기화 실패: %v", err)
}
fmt.Println("database 패키지 초기화 완료")
}

type Pool struct {
size int
}

func newPool(size int) (*Pool, error) {
return &Pool{size: size}, nil
}

init 함수 특징

package mypackage

import "fmt"

var order []string

func init() {
order = append(order, "first init")
fmt.Println("init #1 실행")
}

func init() {
// 같은 파일에 여러 init 함수 가능!
order = append(order, "second init")
fmt.Println("init #2 실행")
}

// init은 인자도, 반환값도 없음
// 직접 호출 불가 (init() 호출 시 컴파일 에러)

init 실행 순서:

  1. 패키지 레벨 변수 초기화
  2. 파일 순서대로 init() 함수 실행
  3. 임포트된 패키지의 init이 먼저 실행됨
package main

import (
_ "myproject/database" // 부수 효과만을 위한 임포트 (init 실행)
"fmt"
)

func main() {
fmt.Println("main 실행")
// 출력 순서:
// database 패키지 초기화 중...
// database 패키지 초기화 완료
// main 실행
}

임포트 별칭과 블랭크 임포트

package main

import (
"fmt"

// 별칭 임포트 — 이름 충돌 해결
mrand "math/rand"
crand "crypto/rand"

// 블랭크 임포트 — init 실행만을 위해
_ "github.com/lib/pq" // PostgreSQL 드라이버 등록

// 점 임포트 — 패키지명 없이 사용 (권장하지 않음)
. "math"
)

func main() {
fmt.Println(mrand.Intn(100)) // math/rand 사용
fmt.Println(crand.Reader) // crypto/rand 사용
fmt.Println(Pi) // math.Pi를 Pi로 직접 사용
}

패키지 구조 실전 예시

현실적인 패키지 구조를 살펴봅니다.

myapp/
├── main.go # package main
├── cmd/
│ └── server/
│ └── main.go # package main (서버 진입점)
├── internal/ # 외부 패키지에서 임포트 불가
│ ├── auth/
│ │ └── auth.go # package auth
│ └── db/
│ └── db.go # package db
├── pkg/ # 외부에 공개할 패키지
│ └── validator/
│ └── validator.go # package validator
└── api/
└── handlers.go # package api
// internal/auth/auth.go
package auth

import (
"crypto/rand"
"encoding/hex"
"errors"
)

// ErrInvalidToken — 공개 에러 (센티넬)
var ErrInvalidToken = errors.New("유효하지 않은 토큰")

// Token — 공개 타입
type Token struct {
Value string
UserID string
ExpiresAt int64
}

// Generate — 공개 함수
func Generate(userID string) (*Token, error) {
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return nil, err
}
return &Token{
Value: hex.EncodeToString(b),
UserID: userID,
}, nil
}

// validate — 비공개 (내부에서만)
func validate(token string) bool {
return len(token) == 64
}

패키지 문서화

Go 패키지에 문서를 추가하려면 패키지 선언 위에 주석을 작성합니다.

// Package geometry는 기하학적 도형 계산을 위한 패키지입니다.
//
// 원, 삼각형, 사각형 등 다양한 도형의 면적과 둘레를 계산합니다.
//
// 사용 예:
//
// c := geometry.NewCircle(5.0)
// fmt.Println(c.Area())
package geometry

go doc 명령으로 문서를 확인할 수 있습니다:

go doc geometry
go doc geometry.Circle
go doc geometry.Circle.Area

핵심 정리

  • 공개/비공개: 첫 글자 대문자 = 공개, 소문자 = 비공개
  • init 함수: 패키지 로드 시 자동 실행, 직접 호출 불가
  • _ 블랭크 임포트: init 실행이나 부수 효과를 위한 임포트
  • 패키지명 = 디렉터리명: 관례적으로 일치시킴
  • internal 패키지: 동일 모듈 내부에서만 사용 가능