1. Go のジェネリックス (Go 1.18+)
ジェネリックを使用すると、型の安全性を維持しながら、さまざまな型で動作する関数と型を作成できます。 Go 1.18 より前では、使用する必要があります インターフェース{} またはコード生成。
1.1.汎用関数
package main
import (
"cmp"
"fmt"
)
// Generic function với type parameter T
func Max[T cmp.Ordered](a, b T) T {
if a > b {
return a
}
return b
}
// Multiple type parameters
func Map[T any, U any](slice []T, fn func(T) U) []U {
result := make([]U, len(slice))
for i, v := range slice {
result[i] = fn(v)
}
return result
}
// Filter
func Filter[T any](slice []T, predicate func(T) bool) []T {
var result []T
for _, v := range slice {
if predicate(v) {
result = append(result, v)
}
}
return result
}
// Reduce
func Reduce[T any, U any](slice []T, initial U, fn func(U, T) U) U {
result := initial
for _, v := range slice {
result = fn(result, v)
}
return result
}
func main() {
// Type inference - Go tự suy luận type
fmt.Println(Max(3, 5)) // int: 5
fmt.Println(Max(3.14, 2.71)) // float64: 3.14
fmt.Println(Max("apple", "banana")) // string: "banana"
// Explicit type
fmt.Println(Max[int](10, 20)) // 20
// Map: []int → []string
nums := []int{1, 2, 3, 4, 5}
strs := Map(nums, func(n int) string {
return fmt.Sprintf("num_%d", n)
})
fmt.Println(strs) // [num_1, num_2, num_3, num_4, num_5]
// Filter
evens := Filter(nums, func(n int) bool {
return n%2 == 0
})
fmt.Println(evens) // [2, 4]
// Reduce
sum := Reduce(nums, 0, func(acc, n int) int {
return acc + n
})
fmt.Println(sum) // 15
}
1.2.型の制約
import "golang.org/x/exp/constraints"
// Built-in constraints (Go 1.21+: cmp package)
// any = interface{} (mọi type)
// comparable = types hỗ trợ == và !=
// cmp.Ordered = types hỗ trợ <, >, <=, >=
// Custom constraint
type Number interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~float32 | ~float64
}
func Sum[T Number](nums []T) T {
var total T
for _, n := range nums {
total += n
}
return total
}
// ~ (tilde) cho phép underlying types
type Celsius float64
type Fahrenheit float64
// Celsius có underlying type float64, nên match ~float64
var temp Celsius = 36.5
fmt.Println(Sum([]Celsius{36.5, 37.0, 36.8})) // OK nhờ ~float64
// Constraint với methods
type Stringer interface {
String() string
}
func PrintAll[T Stringer](items []T) {
for _, item := range items {
fmt.Println(item.String())
}
}
// Composite constraint (methods + types)
type StringLike interface {
~string
Len() int
}
1.3.ジェネリック型 (構造体、インターフェイス)
// Generic Stack
type Stack[T any] struct {
items []T
}
func NewStack[T any]() *Stack[T] {
return &Stack[T]{items: make([]T, 0)}
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() (T, bool) {
if len(s.items) == 0 {
var zero T
return zero, false
}
last := len(s.items) - 1
item := s.items[last]
s.items = s.items[:last]
return item, true
}
func (s *Stack[T]) Peek() (T, bool) {
if len(s.items) == 0 {
var zero T
return zero, false
}
return s.items[len(s.items)-1], true
}
func (s *Stack[T]) Len() int {
return len(s.items)
}
// Generic Result type (like Rust)
type Result[T any] struct {
Value T
Err error
}
func Ok[T any](value T) Result[T] {
return Result[T]{Value: value}
}
func Fail[T any](err error) Result[T] {
return Result[T]{Err: err}
}
func (r Result[T]) Unwrap() (T, error) {
return r.Value, r.Err
}
func main() {
// Stack of ints
intStack := NewStack[int]()
intStack.Push(1)
intStack.Push(2)
intStack.Push(3)
val, ok := intStack.Pop()
fmt.Println(val, ok) // 3, true
// Stack of strings
strStack := NewStack[string]()
strStack.Push("hello")
strStack.Push("world")
// Result
r := Ok(42)
v, err := r.Unwrap()
fmt.Println(v, err) // 42, nil
}
1.4.スライスとマップのパッケージ (Go 1.21+)
import (
"fmt"
"maps"
"slices"
)
func main() {
// slices package - generic slice operations
nums := []int{3, 1, 4, 1, 5, 9, 2, 6}
slices.Sort(nums) // [1, 1, 2, 3, 4, 5, 6, 9]
fmt.Println(slices.Contains(nums, 5)) // true
fmt.Println(slices.Index(nums, 4)) // 4
fmt.Println(slices.Min(nums)) // 1
fmt.Println(slices.Max(nums)) // 9
// slices.SortFunc cho custom sorting
type Person struct {
Name string
Age int
}
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Carol", 28},
}
slices.SortFunc(people, func(a, b Person) int {
return a.Age - b.Age
})
// Compact (remove consecutive duplicates)
sorted := []int{1, 1, 2, 2, 3, 3}
unique := slices.Compact(sorted) // [1, 2, 3]
// maps package
m := map[string]int{"a": 1, "b": 2, "c": 3}
keys := slices.Sorted(maps.Keys(m)) // ["a", "b", "c"]
values := slices.Sorted(maps.Values(m)) // [1, 2, 3]
// Clone
m2 := maps.Clone(m)
// Equal
fmt.Println(maps.Equal(m, m2)) // true
fmt.Println(unique, keys, values)
}
2. パッケージ
2.1.パッケージの基本
// Mỗi file Go thuộc một package
// Package = thư mục chứa các file .go cùng package name
// main package = entry point (có func main)
// Quy tắc đặt tên package:
// - Lowercase, single word: user, auth, config
// - Không dùng camelCase hay snake_case
// - Ngắn gọn, mô tả chức năng
// Visibility rules:
// Exported (public) = Viết hoa chữ cái đầu: User, GetName(), MaxRetries
// Unexported (private) = Viết thường: user, getName(), maxRetries
2.2.パッケージの構成
// Project structure:
// myapp/
// ├── cmd/api/main.go ← package main
// ├── internal/
// │ ├── user/
// │ │ ├── handler.go ← package user
// │ │ ├── service.go ← package user
// │ │ ├── repository.go ← package user
// │ │ └── model.go ← package user
// │ └── auth/
// │ ├── jwt.go ← package auth
// │ └── middleware.go ← package auth
// └── pkg/
// └── validator/
// └── validator.go ← package validator
// internal/ → chỉ import được từ parent module
// pkg/ → public, ai cũng import được
// internal/user/model.go
package user
import "time"
// User - Exported (public)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
password string // unexported (private) - chỉ truy cập trong package user
CreatedAt time.Time `json:"created_at"`
}
// NewUser - Exported constructor
func NewUser(name, email, password string) *User {
return &User{
Name: name,
Email: email,
password: hashPassword(password), // gọi private function
CreatedAt: time.Now(),
}
}
// hashPassword - unexported (private)
func hashPassword(pwd string) string {
// ... hash logic
return pwd
}
2.3. init() 関数
package config
import (
"fmt"
"os"
)
var (
DatabaseURL string
Port string
)
// init() chạy TỰ ĐỘNG khi package được import
// Chạy trước main(), theo thứ tự import
func init() {
DatabaseURL = os.Getenv("DATABASE_URL")
if DatabaseURL == "" {
DatabaseURL = "postgres://localhost:5432/mydb"
}
Port = os.Getenv("PORT")
if Port == "" {
Port = "8080"
}
fmt.Println("Config initialized")
}
// ⚠️ Best practice: Hạn chế dùng init()
// - Khó test, khó debug
// - Implicit side effects
// - Thay bằng explicit initialization: config.Load()
2.4.パターンをインポートする
import (
// Standard library
"fmt"
"net/http"
"os"
// Third-party (blank line separator)
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5"
// Internal packages (blank line separator)
"github.com/yourname/myapp/internal/user"
"github.com/yourname/myapp/internal/auth"
)
// Alias import
import (
stdhttp "net/http" // alias
_ "github.com/lib/pq" // blank import (chỉ chạy init())
. "fmt" // dot import (KHÔNG khuyến khích)
)
// Blank import (_ ) dùng cho:
// - Database drivers: _ "github.com/lib/pq"
// - Image decoders: _ "image/png"
// Chỉ chạy init(), không dùng package trực tiếp
3.Goモジュール
3.1.モジュールの基本
# Khởi tạo module
go mod init github.com/yourname/myapp
# go.mod file
module github.com/yourname/myapp
go 1.23
require (
github.com/gin-gonic/gin v1.10.0
github.com/jackc/pgx/v5 v5.7.1
go.uber.org/zap v1.27.0
)
require (
// indirect dependencies (tự động thêm)
github.com/bytedance/sonic v1.12.4 // indirect
github.com/go-playground/validator/v10 v10.23.0 // indirect
// ...
)
3.2.依存関係の管理
# Thêm dependency
go get github.com/gin-gonic/gin@latest
go get github.com/gin-gonic/[email protected] # specific version
go get github.com/gin-gonic/gin@main # branch
# Update dependency
go get -u github.com/gin-gonic/gin # latest minor/patch
go get -u=patch github.com/gin-gonic/gin # latest patch only
# Update tất cả
go get -u ./...
# Remove unused dependencies
go mod tidy
# Verify dependencies (checksum)
go mod verify
# Download dependencies (cho CI/Docker)
go mod download
# Vendor mode (copy deps vào project)
go mod vendor
go build -mod=vendor ./...
# Xem dependency graph
go mod graph
3.3.セマンティック バージョニング
// Go sử dụng Semantic Versioning: vMAJOR.MINOR.PATCH
// v1.2.3
// MAJOR: Breaking changes (phải thay đổi import path cho v2+)
// MINOR: New features, backwards compatible
// PATCH: Bug fixes
// Major version v2+ phải thay đổi module path:
// v1: github.com/jackc/pgx
// v5: github.com/jackc/pgx/v5
import "github.com/jackc/pgx/v5" // Module path bao gồm /v5
// go.mod
require github.com/jackc/pgx/v5 v5.7.1
3.4.ワークスペース モード (Go 1.18 以降)
# Workspace cho multi-module development
# Khi bạn có nhiều modules liên quan và muốn develop cùng lúc
# Structure:
# workspace/
# ├── go.work
# ├── service-a/
# │ ├── go.mod
# │ └── main.go
# ├── service-b/
# │ ├── go.mod
# │ └── main.go
# └── shared-lib/
# ├── go.mod
# └── utils.go
# Khởi tạo workspace
go work init ./service-a ./service-b ./shared-lib
# go.work file
go 1.23
use (
./service-a
./service-b
./shared-lib
)
# Thêm module vào workspace
go work use ./new-service
# ⚠️ KHÔNG commit go.work vào git cho libraries
# CÓ THỂ commit cho monorepo applications
3.5.ディレクティブを置換する
// go.mod - replace cho local development hoặc fork
module github.com/yourname/myapp
go 1.23
require (
github.com/original/library v1.0.0
)
// Replace với local path (development)
replace github.com/original/library => ../my-fork
// Replace với fork
replace github.com/original/library => github.com/yourfork/library v1.0.1
// ⚠️ Dùng workspace mode thay vì replace khi có thể
4. タグと条件付きコンパイルの構築
// Build tags cho phép include/exclude files khi build
//go:build linux
// +build linux
// File này chỉ compile trên Linux
//go:build !windows
// File này compile trên mọi OS trừ Windows
//go:build integration
// File này chỉ compile khi: go test -tags=integration
// Ví dụ: database driver khác nhau cho từng môi trường
//go:build prod
package config
var DatabaseURL = "postgres://prod-server:5432/mydb"
# Build với tags
go build -tags=prod ./...
go test -tags=integration ./...
5. まとめ
- ジェネリック: 型パラメータ、制約 (any、comparative、cmp.Ordered)、汎用構造体
- スライス/マップ パッケージ: コレクション用の汎用ヘルパー関数 (Go 1.21 以降)
- パッケージ: 大文字 = エクスポート済み、小文字 = 未エクスポート、小さくて集中
- Goモジュール: go.mod、セマンティック バージョニング、go mod tiny、ベンダー モード
- ワークスペース: マルチモジュール開発、go.work
次の部分: ゴルーチンとチャネル — Go の同時実行能力により、Go は高性能システムの最優先の選択肢となります。