[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6G2EB741WAP54R5ZZG706CH":3,"skill-same:01M6G2EB741WAP54R5ZZG706CH":54},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":26,"linkOnly":27,"markdownContent":28,"markdownBody":29,"frontMatter":30,"refName":31,"commitSha":32,"skillDirectory":33,"forksCount":34,"repositoryHtmlUrl":35,"repositoryHomepageUrl":6,"ownerHtmlUrl":36,"ownerBlogUrl":37,"ownerDescription":38,"updatedAt":39,"install":40,"resources":53},"01M6G2EB741WAP54R5ZZG706CH","golang-patterns",null,"Idiomatic Go patterns, best practices, and conventions for building robust, efficient, and maintainable Go applications.","oabdelmaksoud\u002FAgention","oabdelmaksoud","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F50699149?v=4","01M6D5CVVN778ZCDP1WHS816SP","Omar Abdelmaksoud","01M6D8A4TE76V3DCSH3D94VG1V",2,"MIT","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fgolang-patterns\u002FSKILL.md",[],[19,20,21,22,23,24,25],"golang","golang patterns","patterns","go","best practices","applications","conventions","2026-11-10 10:12:30",false,"---\nname: golang-patterns\ndescription: Idiomatic Go patterns, best practices, and conventions for building robust, efficient, and maintainable Go applications.\n---\n\n# Go 開發模式\n\n用於建構穩健、高效且可維護應用程式的慣用 Go 模式和最佳實務。\n\n## 何時啟用\n\n- 撰寫新的 Go 程式碼\n- 審查 Go 程式碼\n- 重構現有 Go 程式碼\n- 設計 Go 套件\u002F模組\n\n## 核心原則\n\n### 1. 簡單與清晰\n\nGo 偏好簡單而非聰明。程式碼應該明顯且易讀。\n\n```go\n\u002F\u002F 良好：清晰直接\nfunc GetUser(id string) (*User, error) {\n    user, err := db.FindUser(id)\n    if err != nil {\n        return nil, fmt.Errorf(\"get user %s: %w\", id, err)\n    }\n    return user, nil\n}\n\n\u002F\u002F 不良：過於聰明\nfunc GetUser(id string) (*User, error) {\n    return func() (*User, error) {\n        if u, e := db.FindUser(id); e == nil {\n            return u, nil\n        } else {\n            return nil, e\n        }\n    }()\n}\n```\n\n### 2. 讓零值有用\n\n設計類型使其零值無需初始化即可立即使用。\n\n```go\n\u002F\u002F 良好：零值有用\ntype Counter struct {\n    mu    sync.Mutex\n    count int \u002F\u002F 零值為 0，可直接使用\n}\n\nfunc (c *Counter) Inc() {\n    c.mu.Lock()\n    c.count++\n    c.mu.Unlock()\n}\n\n\u002F\u002F 良好：bytes.Buffer 零值可用\nvar buf bytes.Buffer\nbuf.WriteString(\"hello\")\n\n\u002F\u002F 不良：需要初始化\ntype BadCounter struct {\n    counts map[string]int \u002F\u002F nil map 會 panic\n}\n```\n\n### 3. 接受介面，回傳結構\n\n函式應接受介面參數並回傳具體類型。\n\n```go\n\u002F\u002F 良好：接受介面，回傳具體類型\nfunc ProcessData(r io.Reader) (*Result, error) {\n    data, err := io.ReadAll(r)\n    if err != nil {\n        return nil, err\n    }\n    return &Result{Data: data}, nil\n}\n\n\u002F\u002F 不良：回傳介面（不必要地隱藏實作細節）\nfunc ProcessData(r io.Reader) (io.Reader, error) {\n    \u002F\u002F ...\n}\n```\n\n## 錯誤處理模式\n\n### 帶上下文的錯誤包裝\n\n```go\n\u002F\u002F 良好：包裝錯誤並加上上下文\nfunc LoadConfig(path string) (*Config, error) {\n    data, err := os.ReadFile(path)\n    if err != nil {\n        return nil, fmt.Errorf(\"load config %s: %w\", path, err)\n    }\n\n    var cfg Config\n    if err := json.Unmarshal(data, &cfg); err != nil {\n        return nil, fmt.Errorf(\"parse config %s: %w\", path, err)\n    }\n\n    return &cfg, nil\n}\n```\n\n### 自訂錯誤類型\n\n```go\n\u002F\u002F 定義領域特定錯誤\ntype ValidationError struct {\n    Field   string\n    Message string\n}\n\nfunc (e *ValidationError) Error() string {\n    return fmt.Sprintf(\"validation failed on %s: %s\", e.Field, e.Message)\n}\n\n\u002F\u002F 常見情況的哨兵錯誤\nvar (\n    ErrNotFound     = errors.New(\"resource not found\")\n    ErrUnauthorized = errors.New(\"unauthorized\")\n    ErrInvalidInput = errors.New(\"invalid input\")\n)\n```\n\n### 使用 errors.Is 和 errors.As 檢查錯誤\n\n```go\nfunc HandleError(err error) {\n    \u002F\u002F 檢查特定錯誤\n    if errors.Is(err, sql.ErrNoRows) {\n        log.Println(\"No records found\")\n        return\n    }\n\n    \u002F\u002F 檢查錯誤類型\n    var validationErr *ValidationError\n    if errors.As(err, &validationErr) {\n        log.Printf(\"Validation error on field %s: %s\",\n            validationErr.Field, validationErr.Message)\n        return\n    }\n\n    \u002F\u002F 未知錯誤\n    log.Printf(\"Unexpected error: %v\", err)\n}\n```\n\n### 絕不忽略錯誤\n\n```go\n\u002F\u002F 不良：用空白識別符忽略錯誤\nresult, _ := doSomething()\n\n\u002F\u002F 良好：處理或明確說明為何安全忽略\nresult, err := doSomething()\nif err != nil {\n    return err\n}\n\n\u002F\u002F 可接受：當錯誤真的不重要時（罕見）\n_ = writer.Close() \u002F\u002F 盡力清理，錯誤在其他地方記錄\n```\n\n## 並行模式\n\n### Worker Pool\n\n```go\nfunc WorkerPool(jobs \u003C-chan Job, results chan\u003C- Result, numWorkers int) {\n    var wg sync.WaitGroup\n\n    for i := 0; i \u003C numWorkers; i++ {\n        wg.Add(1)\n        go func() {\n            defer wg.Done()\n            for job := range jobs {\n                results \u003C- process(job)\n            }\n        }()\n    }\n\n    wg.Wait()\n    close(results)\n}\n```\n\n### 取消和逾時的 Context\n\n```go\nfunc FetchWithTimeout(ctx context.Context, url string) ([]byte, error) {\n    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n    defer cancel()\n\n    req, err := http.NewRequestWithContext(ctx, \"GET\", url, nil)\n    if err != nil {\n        return nil, fmt.Errorf(\"create request: %w\", err)\n    }\n\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        return nil, fmt.Errorf(\"fetch %s: %w\", url, err)\n    }\n    defer resp.Body.Close()\n\n    return io.ReadAll(resp.Body)\n}\n```\n\n### 優雅關閉\n\n```go\nfunc GracefulShutdown(server *http.Server) {\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\n    \u003C-quit\n    log.Println(\"Shutting down server...\")\n\n    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n    defer cancel()\n\n    if err := server.Shutdown(ctx); err != nil {\n        log.Fatalf(\"Server forced to shutdown: %v\", err)\n    }\n\n    log.Println(\"Server exited\")\n}\n```\n\n### 協調 Goroutines 的 errgroup\n\n```go\nimport \"golang.org\u002Fx\u002Fsync\u002Ferrgroup\"\n\nfunc FetchAll(ctx context.Context, urls []string) ([][]byte, error) {\n    g, ctx := errgroup.WithContext(ctx)\n    results := make([][]byte, len(urls))\n\n    for i, url := range urls {\n        i, url := i, url \u002F\u002F 捕獲迴圈變數\n        g.Go(func() error {\n            data, err := FetchWithTimeout(ctx, url)\n            if err != nil {\n                return err\n            }\n            results[i] = data\n            return nil\n        })\n    }\n\n    if err := g.Wait(); err != nil {\n        return nil, err\n    }\n    return results, nil\n}\n```\n\n### 避免 Goroutine 洩漏\n\n```go\n\u002F\u002F 不良：如果 context 被取消會洩漏 goroutine\nfunc leakyFetch(ctx context.Context, url string) \u003C-chan []byte {\n    ch := make(chan []byte)\n    go func() {\n        data, _ := fetch(url)\n        ch \u003C- data \u002F\u002F 如果無接收者會永遠阻塞\n    }()\n    return ch\n}\n\n\u002F\u002F 良好：正確處理取消\nfunc safeFetch(ctx context.Context, url string) \u003C-chan []byte {\n    ch := make(chan []byte, 1) \u002F\u002F 帶緩衝的 channel\n    go func() {\n        data, err := fetch(url)\n        if err != nil {\n            return\n        }\n        select {\n        case ch \u003C- data:\n        case \u003C-ctx.Done():\n        }\n    }()\n    return ch\n}\n```\n\n## 介面設計\n\n### 小而專注的介面\n\n```go\n\u002F\u002F 良好：單一方法介面\ntype Reader interface {\n    Read(p []byte) (n int, err error)\n}\n\ntype Writer interface {\n    Write(p []byte) (n int, err error)\n}\n\ntype Closer interface {\n    Close() error\n}\n\n\u002F\u002F 依需要組合介面\ntype ReadWriteCloser interface {\n    Reader\n    Writer\n    Closer\n}\n```\n\n### 在使用處定義介面\n\n```go\n\u002F\u002F 在消費者套件中，而非提供者\npackage service\n\n\u002F\u002F UserStore 定義此服務需要的內容\ntype UserStore interface {\n    GetUser(id string) (*User, error)\n    SaveUser(user *User) error\n}\n\ntype Service struct {\n    store UserStore\n}\n\n\u002F\u002F 具體實作可以在另一個套件\n\u002F\u002F 它不需要知道這個介面\n```\n\n### 使用型別斷言的可選行為\n\n```go\ntype Flusher interface {\n    Flush() error\n}\n\nfunc WriteAndFlush(w io.Writer, data []byte) error {\n    if _, err := w.Write(data); err != nil {\n        return err\n    }\n\n    \u002F\u002F 如果支援則 Flush\n    if f, ok := w.(Flusher); ok {\n        return f.Flush()\n    }\n    return nil\n}\n```\n\n## 套件組織\n\n### 標準專案結構\n\n```text\nmyproject\u002F\n├── cmd\u002F\n│   └── myapp\u002F\n│       └── main.go           # 進入點\n├── internal\u002F\n│   ├── handler\u002F              # HTTP handlers\n│   ├── service\u002F              # 業務邏輯\n│   ├── repository\u002F           # 資料存取\n│   └── config\u002F               # 設定\n├── pkg\u002F\n│   └── client\u002F               # 公開 API 客戶端\n├── api\u002F\n│   └── v1\u002F                   # API 定義（proto、OpenAPI）\n├── testdata\u002F                 # 測試 fixtures\n├── go.mod\n├── go.sum\n└── Makefile\n```\n\n### 套件命名\n\n```go\n\u002F\u002F 良好：簡短、小寫、無底線\npackage http\npackage json\npackage user\n\n\u002F\u002F 不良：冗長、混合大小寫或冗餘\npackage httpHandler\npackage json_parser\npackage userService \u002F\u002F 冗餘的 'Service' 後綴\n```\n\n### 避免套件層級狀態\n\n```go\n\u002F\u002F 不良：全域可變狀態\nvar db *sql.DB\n\nfunc init() {\n    db, _ = sql.Open(\"postgres\", os.Getenv(\"DATABASE_URL\"))\n}\n\n\u002F\u002F 良好：依賴注入\ntype Server struct {\n    db *sql.DB\n}\n\nfunc NewServer(db *sql.DB) *Server {\n    return &Server{db: db}\n}\n```\n\n## 結構設計\n\n### Functional Options 模式\n\n```go\ntype Server struct {\n    addr    string\n    timeout time.Duration\n    logger  *log.Logger\n}\n\ntype Option func(*Server)\n\nfunc WithTimeout(d time.Duration) Option {\n    return func(s *Server) {\n        s.timeout = d\n    }\n}\n\nfunc WithLogger(l *log.Logger) Option {\n    return func(s *Server) {\n        s.logger = l\n    }\n}\n\nfunc NewServer(addr string, opts ...Option) *Server {\n    s := &Server{\n        addr:    addr,\n        timeout: 30 * time.Second, \u002F\u002F 預設值\n        logger:  log.Default(),    \u002F\u002F 預設值\n    }\n    for _, opt := range opts {\n        opt(s)\n    }\n    return s\n}\n\n\u002F\u002F 使用方式\nserver := NewServer(\":8080\",\n    WithTimeout(60*time.Second),\n    WithLogger(customLogger),\n)\n```\n\n### 嵌入用於組合\n\n```go\ntype Logger struct {\n    prefix string\n}\n\nfunc (l *Logger) Log(msg string) {\n    fmt.Printf(\"[%s] %s\\n\", l.prefix, msg)\n}\n\ntype Server struct {\n    *Logger \u002F\u002F 嵌入 - Server 獲得 Log 方法\n    addr    string\n}\n\nfunc NewServer(addr string) *Server {\n    return &Server{\n        Logger: &Logger{prefix: \"SERVER\"},\n        addr:   addr,\n    }\n}\n\n\u002F\u002F 使用方式\ns := NewServer(\":8080\")\ns.Log(\"Starting...\") \u002F\u002F 呼叫嵌入的 Logger.Log\n```\n\n## 記憶體與效能\n\n### 已知大小時預分配 Slice\n\n```go\n\u002F\u002F 不良：多次擴展 slice\nfunc processItems(items []Item) []Result {\n    var results []Result\n    for _, item := range items {\n        results = append(results, process(item))\n    }\n    return results\n}\n\n\u002F\u002F 良好：單次分配\nfunc processItems(items []Item) []Result {\n    results := make([]Result, 0, len(items))\n    for _, item := range items {\n        results = append(results, process(item))\n    }\n    return results\n}\n```\n\n### 頻繁分配使用 sync.Pool\n\n```go\nvar bufferPool = sync.Pool{\n    New: func() interface{} {\n        return new(bytes.Buffer)\n    },\n}\n\nfunc ProcessRequest(data []byte) []byte {\n    buf := bufferPool.Get().(*bytes.Buffer)\n    defer func() {\n        buf.Reset()\n        bufferPool.Put(buf)\n    }()\n\n    buf.Write(data)\n    \u002F\u002F 處理...\n    return buf.Bytes()\n}\n```\n\n### 避免迴圈中的字串串接\n\n```go\n\u002F\u002F 不良：產生多次字串分配\nfunc join(parts []string) string {\n    var result string\n    for _, p := range parts {\n        result += p + \",\"\n    }\n    return result\n}\n\n\u002F\u002F 良好：使用 strings.Builder 單次分配\nfunc join(parts []string) string {\n    var sb strings.Builder\n    for i, p := range parts {\n        if i > 0 {\n            sb.WriteString(\",\")\n        }\n        sb.WriteString(p)\n    }\n    return sb.String()\n}\n\n\u002F\u002F 最佳：使用標準函式庫\nfunc join(parts []string) string {\n    return strings.Join(parts, \",\")\n}\n```\n\n## Go 工具整合\n\n### 基本指令\n\n```bash\n# 建置和執行\ngo build .\u002F...\ngo run .\u002Fcmd\u002Fmyapp\n\n# 測試\ngo test .\u002F...\ngo test -race .\u002F...\ngo test -cover .\u002F...\n\n# 靜態分析\ngo vet .\u002F...\nstaticcheck .\u002F...\ngolangci-lint run\n\n# 模組管理\ngo mod tidy\ngo mod verify\n\n# 格式化\ngofmt -w .\ngoimports -w .\n```\n\n### 建議的 Linter 設定（.golangci.yml）\n\n```yaml\nlinters:\n  enable:\n    - errcheck\n    - gosimple\n    - govet\n    - ineffassign\n    - staticcheck\n    - unused\n    - gofmt\n    - goimports\n    - misspell\n    - unconvert\n    - unparam\n\nlinters-settings:\n  errcheck:\n    check-type-assertions: true\n  govet:\n    check-shadowing: true\n\nissues:\n  exclude-use-default: false\n```\n\n## 快速參考：Go 慣用語\n\n| 慣用語 | 描述 |\n|-------|------|\n| 接受介面，回傳結構 | 函式接受介面參數，回傳具體類型 |\n| 錯誤是值 | 將錯誤視為一等值，而非例外 |\n| 不要透過共享記憶體通訊 | 使用 channel 在 goroutine 間協調 |\n| 讓零值有用 | 類型應無需明確初始化即可工作 |\n| 一點複製比一點依賴好 | 避免不必要的外部依賴 |\n| 清晰優於聰明 | 優先考慮可讀性而非聰明 |\n| gofmt 不是任何人的最愛但是所有人的朋友 | 總是用 gofmt\u002Fgoimports 格式化 |\n| 提早返回 | 先處理錯誤，保持快樂路徑不縮排 |\n\n## 要避免的反模式\n\n```go\n\u002F\u002F 不良：長函式中的裸返回\nfunc process() (result int, err error) {\n    \u002F\u002F ... 50 行 ...\n    return \u002F\u002F 返回什麼？\n}\n\n\u002F\u002F 不良：使用 panic 作為控制流程\nfunc GetUser(id string) *User {\n    user, err := db.Find(id)\n    if err != nil {\n        panic(err) \u002F\u002F 不要這樣做\n    }\n    return user\n}\n\n\u002F\u002F 不良：在結構中傳遞 context\ntype Request struct {\n    ctx context.Context \u002F\u002F Context 應該是第一個參數\n    ID  string\n}\n\n\u002F\u002F 良好：Context 作為第一個參數\nfunc ProcessRequest(ctx context.Context, id string) error {\n    \u002F\u002F ...\n}\n\n\u002F\u002F 不良：混合值和指標接收器\ntype Counter struct{ n int }\nfunc (c Counter) Value() int { return c.n }    \u002F\u002F 值接收器\nfunc (c *Counter) Increment() { c.n++ }        \u002F\u002F 指標接收器\n\u002F\u002F 選擇一種風格並保持一致\n```\n\n**記住**：Go 程式碼應該以最好的方式無聊 - 可預測、一致且易於理解。有疑慮時，保持簡單。\n","# Go 開發模式\n\n用於建構穩健、高效且可維護應用程式的慣用 Go 模式和最佳實務。\n\n## 何時啟用\n\n- 撰寫新的 Go 程式碼\n- 審查 Go 程式碼\n- 重構現有 Go 程式碼\n- 設計 Go 套件\u002F模組\n\n## 核心原則\n\n### 1. 簡單與清晰\n\nGo 偏好簡單而非聰明。程式碼應該明顯且易讀。\n\n```go\n\u002F\u002F 良好：清晰直接\nfunc GetUser(id string) (*User, error) {\n    user, err := db.FindUser(id)\n    if err != nil {\n        return nil, fmt.Errorf(\"get user %s: %w\", id, err)\n    }\n    return user, nil\n}\n\n\u002F\u002F 不良：過於聰明\nfunc GetUser(id string) (*User, error) {\n    return func() (*User, error) {\n        if u, e := db.FindUser(id); e == nil {\n            return u, nil\n        } else {\n            return nil, e\n        }\n    }()\n}\n```\n\n### 2. 讓零值有用\n\n設計類型使其零值無需初始化即可立即使用。\n\n```go\n\u002F\u002F 良好：零值有用\ntype Counter struct {\n    mu    sync.Mutex\n    count int \u002F\u002F 零值為 0，可直接使用\n}\n\nfunc (c *Counter) Inc() {\n    c.mu.Lock()\n    c.count++\n    c.mu.Unlock()\n}\n\n\u002F\u002F 良好：bytes.Buffer 零值可用\nvar buf bytes.Buffer\nbuf.WriteString(\"hello\")\n\n\u002F\u002F 不良：需要初始化\ntype BadCounter struct {\n    counts map[string]int \u002F\u002F nil map 會 panic\n}\n```\n\n### 3. 接受介面，回傳結構\n\n函式應接受介面參數並回傳具體類型。\n\n```go\n\u002F\u002F 良好：接受介面，回傳具體類型\nfunc ProcessData(r io.Reader) (*Result, error) {\n    data, err := io.ReadAll(r)\n    if err != nil {\n        return nil, err\n    }\n    return &Result{Data: data}, nil\n}\n\n\u002F\u002F 不良：回傳介面（不必要地隱藏實作細節）\nfunc ProcessData(r io.Reader) (io.Reader, error) {\n    \u002F\u002F ...\n}\n```\n\n## 錯誤處理模式\n\n### 帶上下文的錯誤包裝\n\n```go\n\u002F\u002F 良好：包裝錯誤並加上上下文\nfunc LoadConfig(path string) (*Config, error) {\n    data, err := os.ReadFile(path)\n    if err != nil {\n        return nil, fmt.Errorf(\"load config %s: %w\", path, err)\n    }\n\n    var cfg Config\n    if err := json.Unmarshal(data, &cfg); err != nil {\n        return nil, fmt.Errorf(\"parse config %s: %w\", path, err)\n    }\n\n    return &cfg, nil\n}\n```\n\n### 自訂錯誤類型\n\n```go\n\u002F\u002F 定義領域特定錯誤\ntype ValidationError struct {\n    Field   string\n    Message string\n}\n\nfunc (e *ValidationError) Error() string {\n    return fmt.Sprintf(\"validation failed on %s: %s\", e.Field, e.Message)\n}\n\n\u002F\u002F 常見情況的哨兵錯誤\nvar (\n    ErrNotFound     = errors.New(\"resource not found\")\n    ErrUnauthorized = errors.New(\"unauthorized\")\n    ErrInvalidInput = errors.New(\"invalid input\")\n)\n```\n\n### 使用 errors.Is 和 errors.As 檢查錯誤\n\n```go\nfunc HandleError(err error) {\n    \u002F\u002F 檢查特定錯誤\n    if errors.Is(err, sql.ErrNoRows) {\n        log.Println(\"No records found\")\n        return\n    }\n\n    \u002F\u002F 檢查錯誤類型\n    var validationErr *ValidationError\n    if errors.As(err, &validationErr) {\n        log.Printf(\"Validation error on field %s: %s\",\n            validationErr.Field, validationErr.Message)\n        return\n    }\n\n    \u002F\u002F 未知錯誤\n    log.Printf(\"Unexpected error: %v\", err)\n}\n```\n\n### 絕不忽略錯誤\n\n```go\n\u002F\u002F 不良：用空白識別符忽略錯誤\nresult, _ := doSomething()\n\n\u002F\u002F 良好：處理或明確說明為何安全忽略\nresult, err := doSomething()\nif err != nil {\n    return err\n}\n\n\u002F\u002F 可接受：當錯誤真的不重要時（罕見）\n_ = writer.Close() \u002F\u002F 盡力清理，錯誤在其他地方記錄\n```\n\n## 並行模式\n\n### Worker Pool\n\n```go\nfunc WorkerPool(jobs \u003C-chan Job, results chan\u003C- Result, numWorkers int) {\n    var wg sync.WaitGroup\n\n    for i := 0; i \u003C numWorkers; i++ {\n        wg.Add(1)\n        go func() {\n            defer wg.Done()\n            for job := range jobs {\n                results \u003C- process(job)\n            }\n        }()\n    }\n\n    wg.Wait()\n    close(results)\n}\n```\n\n### 取消和逾時的 Context\n\n```go\nfunc FetchWithTimeout(ctx context.Context, url string) ([]byte, error) {\n    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n    defer cancel()\n\n    req, err := http.NewRequestWithContext(ctx, \"GET\", url, nil)\n    if err != nil {\n        return nil, fmt.Errorf(\"create request: %w\", err)\n    }\n\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        return nil, fmt.Errorf(\"fetch %s: %w\", url, err)\n    }\n    defer resp.Body.Close()\n\n    return io.ReadAll(resp.Body)\n}\n```\n\n### 優雅關閉\n\n```go\nfunc GracefulShutdown(server *http.Server) {\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\n    \u003C-quit\n    log.Println(\"Shutting down server...\")\n\n    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n    defer cancel()\n\n    if err := server.Shutdown(ctx); err != nil {\n        log.Fatalf(\"Server forced to shutdown: %v\", err)\n    }\n\n    log.Println(\"Server exited\")\n}\n```\n\n### 協調 Goroutines 的 errgroup\n\n```go\nimport \"golang.org\u002Fx\u002Fsync\u002Ferrgroup\"\n\nfunc FetchAll(ctx context.Context, urls []string) ([][]byte, error) {\n    g, ctx := errgroup.WithContext(ctx)\n    results := make([][]byte, len(urls))\n\n    for i, url := range urls {\n        i, url := i, url \u002F\u002F 捕獲迴圈變數\n        g.Go(func() error {\n            data, err := FetchWithTimeout(ctx, url)\n            if err != nil {\n                return err\n            }\n            results[i] = data\n            return nil\n        })\n    }\n\n    if err := g.Wait(); err != nil {\n        return nil, err\n    }\n    return results, nil\n}\n```\n\n### 避免 Goroutine 洩漏\n\n```go\n\u002F\u002F 不良：如果 context 被取消會洩漏 goroutine\nfunc leakyFetch(ctx context.Context, url string) \u003C-chan []byte {\n    ch := make(chan []byte)\n    go func() {\n        data, _ := fetch(url)\n        ch \u003C- data \u002F\u002F 如果無接收者會永遠阻塞\n    }()\n    return ch\n}\n\n\u002F\u002F 良好：正確處理取消\nfunc safeFetch(ctx context.Context, url string) \u003C-chan []byte {\n    ch := make(chan []byte, 1) \u002F\u002F 帶緩衝的 channel\n    go func() {\n        data, err := fetch(url)\n        if err != nil {\n            return\n        }\n        select {\n        case ch \u003C- data:\n        case \u003C-ctx.Done():\n        }\n    }()\n    return ch\n}\n```\n\n## 介面設計\n\n### 小而專注的介面\n\n```go\n\u002F\u002F 良好：單一方法介面\ntype Reader interface {\n    Read(p []byte) (n int, err error)\n}\n\ntype Writer interface {\n    Write(p []byte) (n int, err error)\n}\n\ntype Closer interface {\n    Close() error\n}\n\n\u002F\u002F 依需要組合介面\ntype ReadWriteCloser interface {\n    Reader\n    Writer\n    Closer\n}\n```\n\n### 在使用處定義介面\n\n```go\n\u002F\u002F 在消費者套件中，而非提供者\npackage service\n\n\u002F\u002F UserStore 定義此服務需要的內容\ntype UserStore interface {\n    GetUser(id string) (*User, error)\n    SaveUser(user *User) error\n}\n\ntype Service struct {\n    store UserStore\n}\n\n\u002F\u002F 具體實作可以在另一個套件\n\u002F\u002F 它不需要知道這個介面\n```\n\n### 使用型別斷言的可選行為\n\n```go\ntype Flusher interface {\n    Flush() error\n}\n\nfunc WriteAndFlush(w io.Writer, data []byte) error {\n    if _, err := w.Write(data); err != nil {\n        return err\n    }\n\n    \u002F\u002F 如果支援則 Flush\n    if f, ok := w.(Flusher); ok {\n        return f.Flush()\n    }\n    return nil\n}\n```\n\n## 套件組織\n\n### 標準專案結構\n\n```text\nmyproject\u002F\n├── cmd\u002F\n│   └── myapp\u002F\n│       └── main.go           # 進入點\n├── internal\u002F\n│   ├── handler\u002F              # HTTP handlers\n│   ├── service\u002F              # 業務邏輯\n│   ├── repository\u002F           # 資料存取\n│   └── config\u002F               # 設定\n├── pkg\u002F\n│   └── client\u002F               # 公開 API 客戶端\n├── api\u002F\n│   └── v1\u002F                   # API 定義（proto、OpenAPI）\n├── testdata\u002F                 # 測試 fixtures\n├── go.mod\n├── go.sum\n└── Makefile\n```\n\n### 套件命名\n\n```go\n\u002F\u002F 良好：簡短、小寫、無底線\npackage http\npackage json\npackage user\n\n\u002F\u002F 不良：冗長、混合大小寫或冗餘\npackage httpHandler\npackage json_parser\npackage userService \u002F\u002F 冗餘的 'Service' 後綴\n```\n\n### 避免套件層級狀態\n\n```go\n\u002F\u002F 不良：全域可變狀態\nvar db *sql.DB\n\nfunc init() {\n    db, _ = sql.Open(\"postgres\", os.Getenv(\"DATABASE_URL\"))\n}\n\n\u002F\u002F 良好：依賴注入\ntype Server struct {\n    db *sql.DB\n}\n\nfunc NewServer(db *sql.DB) *Server {\n    return &Server{db: db}\n}\n```\n\n## 結構設計\n\n### Functional Options 模式\n\n```go\ntype Server struct {\n    addr    string\n    timeout time.Duration\n    logger  *log.Logger\n}\n\ntype Option func(*Server)\n\nfunc WithTimeout(d time.Duration) Option {\n    return func(s *Server) {\n        s.timeout = d\n    }\n}\n\nfunc WithLogger(l *log.Logger) Option {\n    return func(s *Server) {\n        s.logger = l\n    }\n}\n\nfunc NewServer(addr string, opts ...Option) *Server {\n    s := &Server{\n        addr:    addr,\n        timeout: 30 * time.Second, \u002F\u002F 預設值\n        logger:  log.Default(),    \u002F\u002F 預設值\n    }\n    for _, opt := range opts {\n        opt(s)\n    }\n    return s\n}\n\n\u002F\u002F 使用方式\nserver := NewServer(\":8080\",\n    WithTimeout(60*time.Second),\n    WithLogger(customLogger),\n)\n```\n\n### 嵌入用於組合\n\n```go\ntype Logger struct {\n    prefix string\n}\n\nfunc (l *Logger) Log(msg string) {\n    fmt.Printf(\"[%s] %s\\n\", l.prefix, msg)\n}\n\ntype Server struct {\n    *Logger \u002F\u002F 嵌入 - Server 獲得 Log 方法\n    addr    string\n}\n\nfunc NewServer(addr string) *Server {\n    return &Server{\n        Logger: &Logger{prefix: \"SERVER\"},\n        addr:   addr,\n    }\n}\n\n\u002F\u002F 使用方式\ns := NewServer(\":8080\")\ns.Log(\"Starting...\") \u002F\u002F 呼叫嵌入的 Logger.Log\n```\n\n## 記憶體與效能\n\n### 已知大小時預分配 Slice\n\n```go\n\u002F\u002F 不良：多次擴展 slice\nfunc processItems(items []Item) []Result {\n    var results []Result\n    for _, item := range items {\n        results = append(results, process(item))\n    }\n    return results\n}\n\n\u002F\u002F 良好：單次分配\nfunc processItems(items []Item) []Result {\n    results := make([]Result, 0, len(items))\n    for _, item := range items {\n        results = append(results, process(item))\n    }\n    return results\n}\n```\n\n### 頻繁分配使用 sync.Pool\n\n```go\nvar bufferPool = sync.Pool{\n    New: func() interface{} {\n        return new(bytes.Buffer)\n    },\n}\n\nfunc ProcessRequest(data []byte) []byte {\n    buf := bufferPool.Get().(*bytes.Buffer)\n    defer func() {\n        buf.Reset()\n        bufferPool.Put(buf)\n    }()\n\n    buf.Write(data)\n    \u002F\u002F 處理...\n    return buf.Bytes()\n}\n```\n\n### 避免迴圈中的字串串接\n\n```go\n\u002F\u002F 不良：產生多次字串分配\nfunc join(parts []string) string {\n    var result string\n    for _, p := range parts {\n        result += p + \",\"\n    }\n    return result\n}\n\n\u002F\u002F 良好：使用 strings.Builder 單次分配\nfunc join(parts []string) string {\n    var sb strings.Builder\n    for i, p := range parts {\n        if i > 0 {\n            sb.WriteString(\",\")\n        }\n        sb.WriteString(p)\n    }\n    return sb.String()\n}\n\n\u002F\u002F 最佳：使用標準函式庫\nfunc join(parts []string) string {\n    return strings.Join(parts, \",\")\n}\n```\n\n## Go 工具整合\n\n### 基本指令\n\n```bash\n# 建置和執行\ngo build .\u002F...\ngo run .\u002Fcmd\u002Fmyapp\n\n# 測試\ngo test .\u002F...\ngo test -race .\u002F...\ngo test -cover .\u002F...\n\n# 靜態分析\ngo vet .\u002F...\nstaticcheck .\u002F...\ngolangci-lint run\n\n# 模組管理\ngo mod tidy\ngo mod verify\n\n# 格式化\ngofmt -w .\ngoimports -w .\n```\n\n### 建議的 Linter 設定（.golangci.yml）\n\n```yaml\nlinters:\n  enable:\n    - errcheck\n    - gosimple\n    - govet\n    - ineffassign\n    - staticcheck\n    - unused\n    - gofmt\n    - goimports\n    - misspell\n    - unconvert\n    - unparam\n\nlinters-settings:\n  errcheck:\n    check-type-assertions: true\n  govet:\n    check-shadowing: true\n\nissues:\n  exclude-use-default: false\n```\n\n## 快速參考：Go 慣用語\n\n| 慣用語 | 描述 |\n|-------|------|\n| 接受介面，回傳結構 | 函式接受介面參數，回傳具體類型 |\n| 錯誤是值 | 將錯誤視為一等值，而非例外 |\n| 不要透過共享記憶體通訊 | 使用 channel 在 goroutine 間協調 |\n| 讓零值有用 | 類型應無需明確初始化即可工作 |\n| 一點複製比一點依賴好 | 避免不必要的外部依賴 |\n| 清晰優於聰明 | 優先考慮可讀性而非聰明 |\n| gofmt 不是任何人的最愛但是所有人的朋友 | 總是用 gofmt\u002Fgoimports 格式化 |\n| 提早返回 | 先處理錯誤，保持快樂路徑不縮排 |\n\n## 要避免的反模式\n\n```go\n\u002F\u002F 不良：長函式中的裸返回\nfunc process() (result int, err error) {\n    \u002F\u002F ... 50 行 ...\n    return \u002F\u002F 返回什麼？\n}\n\n\u002F\u002F 不良：使用 panic 作為控制流程\nfunc GetUser(id string) *User {\n    user, err := db.Find(id)\n    if err != nil {\n        panic(err) \u002F\u002F 不要這樣做\n    }\n    return user\n}\n\n\u002F\u002F 不良：在結構中傳遞 context\ntype Request struct {\n    ctx context.Context \u002F\u002F Context 應該是第一個參數\n    ID  string\n}\n\n\u002F\u002F 良好：Context 作為第一個參數\nfunc ProcessRequest(ctx context.Context, id string) error {\n    \u002F\u002F ...\n}\n\n\u002F\u002F 不良：混合值和指標接收器\ntype Counter struct{ n int }\nfunc (c Counter) Value() int { return c.n }    \u002F\u002F 值接收器\nfunc (c *Counter) Increment() { c.n++ }        \u002F\u002F 指標接收器\n\u002F\u002F 選擇一種風格並保持一致\n```\n\n**記住**：Go 程式碼應該以最好的方式無聊 - 可預測、一致且易於理解。有疑慮時，保持簡單。\n",{"name":5,"description":7},"main","a318f48de3c5718e8ea2e9f6fae7790e8a759e85","upstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fgolang-patterns",0,"https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fo-abdelmaksoud\u002F","Full-Stack Engineer | AI Systems Architect | Building autonomous multi-agent systems","2026-03-08 21:23:03",{"source":8,"skillName":5,"commands":41,"prompt":51,"zipAvailable":52},[42,45,48],{"tool":43,"command":44},"npx","npx skills add oabdelmaksoud\u002FAgention --skill golang-patterns",{"tool":46,"command":47},"bunx","bunx skills add oabdelmaksoud\u002FAgention --skill golang-patterns",{"tool":49,"command":50},"pnpm","pnpm dlx skills add oabdelmaksoud\u002FAgention --skill golang-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fgolang-patterns\u002FSKILL.md",true,[],[55,79,93,126,150,170],{"skillNo":56,"name":57,"nameZh":6,"description":58,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":59,"categories":60,"keywords":66,"publishedAt":26},"01M6G2QFCBNBYAJF2KTK85G9A6","visa-doc-translate","Translate visa application documents (images) to English and create a bilingual PDF with original and translation","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fvisa-doc-translate\u002FSKILL.md",[61],{"categoryNo":62,"categoryName":63,"taxonomyType":64,"taxonomyTypeDesc":65},"01JBSEEDCAT000000000000002","文档处理","SCENARIO","使用场景",[67,68,69,70,71,72,73,74,75,76,77,78],"translate","doc","visa doc translate","bilingual","with","english","application","PDF","translation","documents","create","images",{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":26},"01M6G2QB09TSK6BY4ME5X20EVQ","verification-loop","A comprehensive verification system for Claude Code sessions.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[86,87,88,89,90,91,92],"verification","loop","verification loop","sessions","code","claude code sessions","system",{"skillNo":94,"name":95,"nameZh":6,"description":96,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":110,"publishedAt":26},"01M6G2Q6V2F7G03VAAF27FXPJR","tdd-workflow","Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[99,102,105],{"categoryNo":100,"categoryName":101,"taxonomyType":64,"taxonomyTypeDesc":65},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":103,"categoryName":104,"taxonomyType":64,"taxonomyTypeDesc":65},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":106,"categoryName":107,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[111,112,113,114,115,116,117,118,119,90,120,121,122,123,71,124,125],"workflow","tdd","tdd workflow","use","unit","coverage","refactoring","e2e","integration","development","e2e tests","tests","driven","test","writing",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":26},"01M6G2Q359YJRWAR2PFCEQAXF3","swiftui-patterns","SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS\u002FmacOS UI best practices.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswiftui-patterns\u002FSKILL.md",[],[21,133,134,135,136,137,138,23,139,140,141,142,143,144,145,146,147,148,149,71],"swiftui","swiftui patterns","architecture","macos","performance","state management","state","ui","Optimization","ios","architecture patterns","Composition","performance optimization","view","management","swiftui architecture","navigation",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":157,"publishedAt":26},"01M6G2PY8B2FWZTWPZ84H83Y7C","swift-protocol-di-testing","Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-protocol-di-testing\u002FSKILL.md",[156],{"categoryNo":100,"categoryName":101,"taxonomyType":64,"taxonomyTypeDesc":65},[158,159,160,161,90,162,163,164,165,92,166,167,168,169],"swift protocol di testing","protocol","swift","testing","protocols","file","network","injection","dependency","swift testing","dependency injection","mock",{"skillNo":171,"name":172,"nameZh":6,"description":173,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":174,"categories":175,"keywords":176,"publishedAt":26},"01M6G2PSCN2GXV9FFZDRRRWVB6","swift-concurrency-6-2","Swift 6.2 Approachable Concurrency — single-threaded by default, @concurrent for explicit background offloading, isolated conformances for main actor types.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-concurrency-6-2\u002FSKILL.md",[],[177,178,179,160,180,31,181],"concurrency","swift concurrency","swift concurrency 6 2","default","types"]