[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F3HQJG2TYP2Z0V21JS88J9":3,"skill-same:01M6F3HQJG2TYP2Z0V21JS88J9":64},{"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":34,"linkOnly":35,"markdownContent":36,"markdownBody":37,"frontMatter":38,"refName":41,"commitSha":42,"skillDirectory":43,"forksCount":44,"repositoryHtmlUrl":45,"repositoryHomepageUrl":46,"ownerHtmlUrl":47,"ownerBlogUrl":6,"ownerDescription":48,"updatedAt":49,"install":50,"resources":63},"01M6F3HQJG2TYP2Z0V21JS88J9","go-functional-options",null,"Use when designing a Go constructor or factory function with optional configuration — especially with 3+ optional parameters or extensible APIs. Also use when building a New* function that takes many settings, even if they don't mention \"functional options\" by name. Does not cover general function design (see go-functions).","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fcxuu\u002Fgolang-skills\u002Fgo-functional-options\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33],"go","options","functional","go functional options","design","settings","factory","guide","use","general","functions","configuration","name","style","with","2026-11-10 10:12:30",false,"---\nname: go-functional-options\ndescription: Use when designing a Go constructor or factory function with optional configuration — especially with 3+ optional parameters or extensible APIs. Also use when building a New* function that takes many settings, even if they don't mention \"functional options\" by name. Does not cover general function design (see go-functions).\nlicense: Apache-2.0\nmetadata:\n  sources: \"Uber Style Guide\"\n---\n\n# Functional Options Pattern\n\nFunctional options is a pattern where you declare an opaque `Option` type that records information in an internal struct. The constructor accepts a variadic number of these options and applies them to configure the result.\n\n## When to Use\n\nUse functional options when:\n\n- **3+ optional arguments** on constructors or public APIs\n- **Extensible APIs** that may gain new options over time\n- **Clean caller experience** is important (no need to pass defaults)\n\n## The Pattern\n\n### Core Components\n\n1. **Unexported `options` struct** - holds all configuration\n2. **Exported `Option` interface** - with unexported `apply` method\n3. **Option types** - implement the interface\n4. **`With*` constructors** - create options\n\n### Option Interface\n\n```go\ntype Option interface {\n    apply(*options)\n}\n```\n\nThe unexported `apply` method ensures only options from this package can be used.\n\n## Complete Implementation\n\n```go\npackage db\n\nimport \"go.uber.org\u002Fzap\"\n\n\u002F\u002F options holds all configuration for opening a connection.\ntype options struct {\n    cache  bool\n    logger *zap.Logger\n}\n\n\u002F\u002F Option configures how we open the connection.\ntype Option interface {\n    apply(*options)\n}\n\n\u002F\u002F cacheOption implements Option for cache setting (simple type alias).\ntype cacheOption bool\n\nfunc (c cacheOption) apply(opts *options) {\n    opts.cache = bool(c)\n}\n\n\u002F\u002F WithCache enables or disables caching.\nfunc WithCache(c bool) Option {\n    return cacheOption(c)\n}\n\n\u002F\u002F loggerOption implements Option for logger setting (struct for pointers).\ntype loggerOption struct {\n    Log *zap.Logger\n}\n\nfunc (l loggerOption) apply(opts *options) {\n    opts.logger = l.Log\n}\n\n\u002F\u002F WithLogger sets the logger for the connection.\nfunc WithLogger(log *zap.Logger) Option {\n    return loggerOption{Log: log}\n}\n\n\u002F\u002F Open creates a connection.\nfunc Open(addr string, opts ...Option) (*Connection, error) {\n    \u002F\u002F Start with defaults\n    options := options{\n        cache:  defaultCache,\n        logger: zap.NewNop(),\n    }\n\n    \u002F\u002F Apply all provided options\n    for _, o := range opts {\n        o.apply(&options)\n    }\n\n    \u002F\u002F Use options.cache and options.logger...\n    return &Connection{}, nil\n}\n```\n\n## Usage Examples\n\n### Without Functional Options (Bad)\n\n```go\n\u002F\u002F Caller must always provide all parameters, even defaults\ndb.Open(addr, db.DefaultCache, zap.NewNop())\ndb.Open(addr, db.DefaultCache, log)\ndb.Open(addr, false \u002F* cache *\u002F, zap.NewNop())\ndb.Open(addr, false \u002F* cache *\u002F, log)\n```\n\n### With Functional Options (Good)\n\n```go\n\u002F\u002F Only provide options when needed\ndb.Open(addr)\ndb.Open(addr, db.WithLogger(log))\ndb.Open(addr, db.WithCache(false))\ndb.Open(\n    addr,\n    db.WithCache(false),\n    db.WithLogger(log),\n)\n```\n\n## Comparison: Functional Options vs Config Struct\n\n| Aspect | Functional Options | Config Struct |\n|--------|-------------------|---------------|\n| **Extensibility** | Add new `With*` functions | Add new fields (may break) |\n| **Defaults** | Built into constructor | Zero values or separate defaults |\n| **Caller experience** | Only specify what differs | Must construct entire struct |\n| **Testability** | Options are comparable | Struct comparison |\n| **Complexity** | More boilerplate | Simpler setup |\n\n**Prefer Config Struct when**: Fewer than 3 options, options rarely change, all options usually specified together, or internal APIs only.\n\n> Read [references\u002FOPTIONS-VS-STRUCTS.md](references\u002FOPTIONS-VS-STRUCTS.md) when deciding between functional options and config structs, designing a config struct API with proper defaults, or evaluating the hybrid approach for complex constructors.\n\n## Why Not Closures?\n\nAn alternative implementation uses closures:\n\n```go\n\u002F\u002F Closure approach (not recommended)\ntype Option func(*options)\n\nfunc WithCache(c bool) Option {\n    return func(o *options) { o.cache = c }\n}\n```\n\nThe interface approach is preferred because:\n\n1. **Testability** - Options can be compared in tests and mocks\n2. **Debuggability** - Options can implement `fmt.Stringer`\n3. **Flexibility** - Options can implement additional interfaces\n4. **Visibility** - Option types are visible in documentation\n\n## Quick Reference\n\n```go\n\u002F\u002F 1. Unexported options struct with defaults\ntype options struct {\n    field1 Type1\n    field2 Type2\n}\n\n\u002F\u002F 2. Exported Option interface, unexported method\ntype Option interface {\n    apply(*options)\n}\n\n\u002F\u002F 3. Option type + apply + With* constructor\ntype field1Option Type1\n\nfunc (o field1Option) apply(opts *options) { opts.field1 = Type1(o) }\nfunc WithField1(v Type1) Option            { return field1Option(v) }\n\n\u002F\u002F 4. Constructor applies options over defaults\nfunc New(required string, opts ...Option) (*Thing, error) {\n    o := options{field1: defaultField1, field2: defaultField2}\n    for _, opt := range opts {\n        opt.apply(&o)\n    }\n    \u002F\u002F ...\n}\n```\n\n### Checklist\n\n- [ ] `options` struct is unexported\n- [ ] `Option` interface has unexported `apply` method\n- [ ] Each option has a `With*` constructor\n- [ ] Defaults are set before applying options\n- [ ] Required parameters are separate from `...Option`\n\n## Related Skills\n\n- **Interface design**: See [go-interfaces](..\u002Fgo-interfaces\u002FSKILL.md) when designing the `Option` interface or choosing between interface and closure approaches\n- **Naming conventions**: See [go-naming](..\u002Fgo-naming\u002FSKILL.md) when naming `With*` constructors, option types, or the unexported options struct\n- **Function design**: See [go-functions](..\u002Fgo-functions\u002FSKILL.md) when organizing constructors within a file or formatting variadic signatures\n- **Documentation**: See [go-documentation](..\u002Fgo-documentation\u002FSKILL.md) when documenting `Option` types, `With*` functions, or constructor behavior\n\n### External Resources\n\n- [Self-referential functions and the design of options](https:\u002F\u002Fcommandcenter.blogspot.com\u002F2014\u002F01\u002Fself-referential-functions-and-design.html) - Rob Pike\n- [Functional options for friendly APIs](https:\u002F\u002Fdave.cheney.net\u002F2014\u002F10\u002F17\u002Ffunctional-options-for-friendly-apis) - Dave Cheney\n\n","# Functional Options Pattern\n\nFunctional options is a pattern where you declare an opaque `Option` type that records information in an internal struct. The constructor accepts a variadic number of these options and applies them to configure the result.\n\n## When to Use\n\nUse functional options when:\n\n- **3+ optional arguments** on constructors or public APIs\n- **Extensible APIs** that may gain new options over time\n- **Clean caller experience** is important (no need to pass defaults)\n\n## The Pattern\n\n### Core Components\n\n1. **Unexported `options` struct** - holds all configuration\n2. **Exported `Option` interface** - with unexported `apply` method\n3. **Option types** - implement the interface\n4. **`With*` constructors** - create options\n\n### Option Interface\n\n```go\ntype Option interface {\n    apply(*options)\n}\n```\n\nThe unexported `apply` method ensures only options from this package can be used.\n\n## Complete Implementation\n\n```go\npackage db\n\nimport \"go.uber.org\u002Fzap\"\n\n\u002F\u002F options holds all configuration for opening a connection.\ntype options struct {\n    cache  bool\n    logger *zap.Logger\n}\n\n\u002F\u002F Option configures how we open the connection.\ntype Option interface {\n    apply(*options)\n}\n\n\u002F\u002F cacheOption implements Option for cache setting (simple type alias).\ntype cacheOption bool\n\nfunc (c cacheOption) apply(opts *options) {\n    opts.cache = bool(c)\n}\n\n\u002F\u002F WithCache enables or disables caching.\nfunc WithCache(c bool) Option {\n    return cacheOption(c)\n}\n\n\u002F\u002F loggerOption implements Option for logger setting (struct for pointers).\ntype loggerOption struct {\n    Log *zap.Logger\n}\n\nfunc (l loggerOption) apply(opts *options) {\n    opts.logger = l.Log\n}\n\n\u002F\u002F WithLogger sets the logger for the connection.\nfunc WithLogger(log *zap.Logger) Option {\n    return loggerOption{Log: log}\n}\n\n\u002F\u002F Open creates a connection.\nfunc Open(addr string, opts ...Option) (*Connection, error) {\n    \u002F\u002F Start with defaults\n    options := options{\n        cache:  defaultCache,\n        logger: zap.NewNop(),\n    }\n\n    \u002F\u002F Apply all provided options\n    for _, o := range opts {\n        o.apply(&options)\n    }\n\n    \u002F\u002F Use options.cache and options.logger...\n    return &Connection{}, nil\n}\n```\n\n## Usage Examples\n\n### Without Functional Options (Bad)\n\n```go\n\u002F\u002F Caller must always provide all parameters, even defaults\ndb.Open(addr, db.DefaultCache, zap.NewNop())\ndb.Open(addr, db.DefaultCache, log)\ndb.Open(addr, false \u002F* cache *\u002F, zap.NewNop())\ndb.Open(addr, false \u002F* cache *\u002F, log)\n```\n\n### With Functional Options (Good)\n\n```go\n\u002F\u002F Only provide options when needed\ndb.Open(addr)\ndb.Open(addr, db.WithLogger(log))\ndb.Open(addr, db.WithCache(false))\ndb.Open(\n    addr,\n    db.WithCache(false),\n    db.WithLogger(log),\n)\n```\n\n## Comparison: Functional Options vs Config Struct\n\n| Aspect | Functional Options | Config Struct |\n|--------|-------------------|---------------|\n| **Extensibility** | Add new `With*` functions | Add new fields (may break) |\n| **Defaults** | Built into constructor | Zero values or separate defaults |\n| **Caller experience** | Only specify what differs | Must construct entire struct |\n| **Testability** | Options are comparable | Struct comparison |\n| **Complexity** | More boilerplate | Simpler setup |\n\n**Prefer Config Struct when**: Fewer than 3 options, options rarely change, all options usually specified together, or internal APIs only.\n\n> Read [references\u002FOPTIONS-VS-STRUCTS.md](references\u002FOPTIONS-VS-STRUCTS.md) when deciding between functional options and config structs, designing a config struct API with proper defaults, or evaluating the hybrid approach for complex constructors.\n\n## Why Not Closures?\n\nAn alternative implementation uses closures:\n\n```go\n\u002F\u002F Closure approach (not recommended)\ntype Option func(*options)\n\nfunc WithCache(c bool) Option {\n    return func(o *options) { o.cache = c }\n}\n```\n\nThe interface approach is preferred because:\n\n1. **Testability** - Options can be compared in tests and mocks\n2. **Debuggability** - Options can implement `fmt.Stringer`\n3. **Flexibility** - Options can implement additional interfaces\n4. **Visibility** - Option types are visible in documentation\n\n## Quick Reference\n\n```go\n\u002F\u002F 1. Unexported options struct with defaults\ntype options struct {\n    field1 Type1\n    field2 Type2\n}\n\n\u002F\u002F 2. Exported Option interface, unexported method\ntype Option interface {\n    apply(*options)\n}\n\n\u002F\u002F 3. Option type + apply + With* constructor\ntype field1Option Type1\n\nfunc (o field1Option) apply(opts *options) { opts.field1 = Type1(o) }\nfunc WithField1(v Type1) Option            { return field1Option(v) }\n\n\u002F\u002F 4. Constructor applies options over defaults\nfunc New(required string, opts ...Option) (*Thing, error) {\n    o := options{field1: defaultField1, field2: defaultField2}\n    for _, opt := range opts {\n        opt.apply(&o)\n    }\n    \u002F\u002F ...\n}\n```\n\n### Checklist\n\n- [ ] `options` struct is unexported\n- [ ] `Option` interface has unexported `apply` method\n- [ ] Each option has a `With*` constructor\n- [ ] Defaults are set before applying options\n- [ ] Required parameters are separate from `...Option`\n\n## Related Skills\n\n- **Interface design**: See [go-interfaces](..\u002Fgo-interfaces\u002FSKILL.md) when designing the `Option` interface or choosing between interface and closure approaches\n- **Naming conventions**: See [go-naming](..\u002Fgo-naming\u002FSKILL.md) when naming `With*` constructors, option types, or the unexported options struct\n- **Function design**: See [go-functions](..\u002Fgo-functions\u002FSKILL.md) when organizing constructors within a file or formatting variadic signatures\n- **Documentation**: See [go-documentation](..\u002Fgo-documentation\u002FSKILL.md) when documenting `Option` types, `With*` functions, or constructor behavior\n\n### External Resources\n\n- [Self-referential functions and the design of options](https:\u002F\u002Fcommandcenter.blogspot.com\u002F2014\u002F01\u002Fself-referential-functions-and-design.html) - Rob Pike\n- [Functional options for friendly APIs](https:\u002F\u002Fdave.cheney.net\u002F2014\u002F10\u002F17\u002Ffunctional-options-for-friendly-apis) - Dave Cheney\n\n",{"name":5,"license":15,"metadata":39,"description":7},{"sources":40},"Uber Style Guide","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Fcxuu\u002Fgolang-skills\u002Fgo-functional-options",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill go-functional-options",{"tool":56,"command":57},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill go-functional-options",{"tool":59,"command":60},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill go-functional-options","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fcxuu\u002Fgolang-skills\u002Fgo-functional-options\u002FSKILL.md",true,[],[65,80,90,99,105,112],{"skillNo":66,"name":67,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":68,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":76,"publishedAt":34},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[71],{"categoryNo":72,"categoryName":73,"taxonomyType":74,"taxonomyTypeDesc":75},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[77,78,79],"model","model hierarchy","model hierarchy skill",{"skillNo":81,"name":82,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":68,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":86,"publishedAt":34},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[85],{"categoryNo":72,"categoryName":73,"taxonomyType":74,"taxonomyTypeDesc":75},[87,88,89],"MCP","zoom","zoom mcp",{"skillNo":91,"name":92,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":68,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":34},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[96,97,98,88],"sdk","zoom apps sdk","apps",{"skillNo":100,"name":101,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":68,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":104,"publishedAt":34},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[101],{"skillNo":106,"name":107,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":68,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":111,"publishedAt":34},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[110],{"categoryNo":72,"categoryName":73,"taxonomyType":74,"taxonomyTypeDesc":75},[107],{"skillNo":113,"name":114,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":68,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":117,"publishedAt":34},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[114]]