optparams

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 0 Imported by: 60

README

optparams

Go Reference Go Version Release CI

用于管理“关键字参数”(函数选项, functional options)风格的模块,思路参考自 grpc 项目的 option 设计。借助 Go 泛型,只需写少量代码即可获得类型安全的可选参数。

A tiny module for managing keyword arguments in the functional-options style, inspired by the option design of the gRPC project. With Go generics you get type-safe optional parameters with very little boilerplate.

安装 / Install

$ go get github.com/Golang-Tools/optparams@latest

需要 Go 1.22 及以上。Requires Go 1.22+.

快速上手 / Quick Start

package main

import (
	"fmt"

	"github.com/Golang-Tools/optparams"
)

// 1. 定义一个关键字参数的结构体 / define your options struct
type NameOpt struct {
	Name string
}

// 2. 定义可用的参数项,一般用 With 开头 / define each option, prefix with With
func WithName(name string) optparams.Option[NameOpt] {
	return optparams.NewFuncOption(func(o *NameOpt) {
		o.Name = name
	})
}

// 3. 函数接收 ...optparams.Option[T],并解析出完整配置 / accept variadic options
func Greet(opts ...optparams.Option[NameOpt]) {
	opt := optparams.GetOption(&NameOpt{Name: "guest"}, opts...)
	fmt.Println("hello", opt.Name)
}

func main() {
	Greet(WithName("alice")) // hello alice
}

API 语义 / Semantics

GetOption Apply
语义 Semantics 拷贝后解析(纯函数) resolve from a copy (pure) 原地应用 apply in place
是否修改入参 mutates input 否 no 是 yes
返回值 returns 新指针(副本) a fresh copy 传入的 target the target you passed
适用场景 use case 从可复用的共享默认值产出新配置 对存量配置叠加/覆盖(如 Init)
  • GetOption(纯函数 / pure):先对 *defaultopt 做一次拷贝,再把选项应用到拷贝上。可安全传入包级共享默认值,多次调用互不污染。若 defaultopt 为 nil,则以 T 的零值为起点。

    It copies *defaultopt first, then applies the options to the copy, so shared defaults are never polluted. A nil default starts from the zero value of T.

  • Apply(原地 / in place):直接把选项作用到已存在的结构体上,返回该结构体。用于对已有配置做叠加/覆盖,例如 Init。

    It applies options directly onto an existing struct, useful for overlaying/initializing live config. target must not be nil.

  • Combine:把一组选项合并为单个 Option,便于复用与二次封装。

    Merges several options into a single Option, handy for reuse and wrapping.

边界情况 / Edge cases

  • opts 中的 nil 选项会被安全跳过。Nil options in opts are skipped safely.
  • 默认值拷贝是浅拷贝:若 T 含指针/切片/map 等引用字段,选项对这些字段内容的修改仍会作用到底层共享对象。The default copy is shallow: options that mutate reference fields (pointer/slice/map) inside T still affect the shared underlying object.
  • 命名约定:选项构造函数建议以 With 开头。Convention: prefix option constructors with With.

迁移说明 / Migration (v0.0.1 → v1.0.0)

GetOption 在 v1.0.0 改为拷贝语义(纯函数)。如果你依赖旧的“原地修改”行为,请改调 Apply;需要“拷贝后解析”时继续使用 GetOption。

In v1.0.0 GetOption became copy-based (pure). If you relied on the old in-place behaviour, switch those calls to Apply; keep using GetOption when you want copy-based resolution.

文档 / Docs

完整的包文档见 pkg.go.dev: https://pkg.go.dev/github.com/Golang-Tools/optparams。Full package docs on pkg.go.dev.

License

MIT

Documentation

Overview

Package optparams 管理“关键字参数”(函数选项, functional options)风格的模块。 思路参考自 grpc 项目的 option 设计,借助 Go 泛型消除重复代码。

核心语义区分:

  • GetOption 是“纯函数”风格:基于传入的默认值做一次拷贝再解析,不会污染可复用的共享默认结构。
  • Apply 是“原地”风格:直接把选项作用到已存在的结构体上,适用于对存量配置做叠加/覆盖(如 Init)。

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Apply added in v1.0.0

func Apply[T any](target *T, opts ...Option[T]) *T

Apply 将一组关键字参数原地作用到 target 上,并返回 target(原地语义)。

适用于对已存在的配置做叠加/覆盖(例如 Init 场景),与 GetOption 的“拷贝后解析”互补。 opts 中为 nil 的选项会被跳过;target 不能为 nil。

Example
package main

import (
	"fmt"

	"github.com/Golang-Tools/optparams"
)

// PersonOpt 用于示例的关键字参数结构。
type PersonOpt struct {
	Name string
	Age  int
}

// WithAge 返回设置年龄的选项。
func WithAge(age int) optparams.Option[PersonOpt] {
	return optparams.NewFuncOption(func(o *PersonOpt) {
		o.Age = age
	})
}

func main() {
	o := &PersonOpt{Name: "guest", Age: 18}
	optparams.Apply(o, WithAge(30)) // 原地叠加,不改变 Name
	fmt.Printf("%s(%d)\n", o.Name, o.Age)
}
Output:
guest(30)

func GetOption

func GetOption[T any](defaultopt *T, opts ...Option[T]) *T

GetOption 解析一组关键字参数并返回完整的配置实例(纯函数语义)。

它不会修改传入的 defaultopt:会先对 *defaultopt 做一次(浅)拷贝,再把 opts 应用到拷贝上并返回拷贝的指针。因此可以安全地传入可复用的共享默认值 (例如包级变量),多次调用也不会互相污染。 当 defaultopt 为 nil 时,以 T 的零值为起点解析;opts 中为 nil 的选项会被跳过。

注意:此处为浅拷贝;若 T 中包含指针、切片或 map 等引用类型字段,选项对这些 字段内容的修改仍会作用到底层共享对象。

需要“原地修改已有结构体”时,请改用 Apply。

Example
package main

import (
	"fmt"

	"github.com/Golang-Tools/optparams"
)

// PersonOpt 用于示例的关键字参数结构。
type PersonOpt struct {
	Name string
	Age  int
}

// WithName 返回设置姓名的选项。
func WithName(name string) optparams.Option[PersonOpt] {
	return optparams.NewFuncOption(func(o *PersonOpt) {
		o.Name = name
	})
}

// WithAge 返回设置年龄的选项。
func WithAge(age int) optparams.Option[PersonOpt] {
	return optparams.NewFuncOption(func(o *PersonOpt) {
		o.Age = age
	})
}

func main() {
	opt := optparams.GetOption(&PersonOpt{Name: "guest", Age: 18}, WithName("alice"), WithAge(30))
	fmt.Printf("%s(%d)\n", opt.Name, opt.Age)
}
Output:
alice(30)
Example (SharedDefault)

ExampleGetOption_sharedDefault 展示 GetOption 不会污染可复用的共享默认值。

package main

import (
	"fmt"

	"github.com/Golang-Tools/optparams"
)

// PersonOpt 用于示例的关键字参数结构。
type PersonOpt struct {
	Name string
	Age  int
}

// WithName 返回设置姓名的选项。
func WithName(name string) optparams.Option[PersonOpt] {
	return optparams.NewFuncOption(func(o *PersonOpt) {
		o.Name = name
	})
}

// WithAge 返回设置年龄的选项。
func WithAge(age int) optparams.Option[PersonOpt] {
	return optparams.NewFuncOption(func(o *PersonOpt) {
		o.Age = age
	})
}

func main() {
	shared := &PersonOpt{Name: "guest", Age: 18}
	a := optparams.GetOption(shared, WithName("alice"))
	b := optparams.GetOption(shared, WithAge(40))
	fmt.Printf("shared=%s/%s age=%d\n", shared.Name, a.Name, b.Age)
}
Output:
shared=guest/alice age=40

Types

type FuncOption

type FuncOption[T any] struct {
	// contains filtered or unexported fields
}

FuncOption 是基于闭包实现的关键字参数项,通常作为 NewFuncOption 的返回值。 @generic T any 关键字参数对应的结构

func NewFuncOption

func NewFuncOption[T any](f func(*T)) *FuncOption[T]

NewFuncOption 构造一个基于函数的关键字参数项。

例子:

func WithName(name string) optparams.Option[NameOpt] {
	return optparams.NewFuncOption(
		func(o *NameOpt) {
			o.Name = name
		})
}

@generic T any 关键字参数对应的结构

func (*FuncOption[T]) Apply

func (fo *FuncOption[T]) Apply(do *T)

Apply 将内部保存的函数作用到目标结构体 do 上。

type Option

type Option[T any] interface {
	Apply(*T)
}

Option 是关键字参数项的形参类型。 任何实现了 Apply(*T) 方法的类型都可作为 Option[T] 使用。 @generic T any 关键字参数对应的结构

func Combine added in v1.0.0

func Combine[T any](opts ...Option[T]) Option[T]

Combine 将一组选项合并为单个 Option,便于复用与二次封装。 返回的选项会按给定顺序依次应用组内各选项;组内为 nil 的选项会被跳过。

Example
package main

import (
	"fmt"

	"github.com/Golang-Tools/optparams"
)

// PersonOpt 用于示例的关键字参数结构。
type PersonOpt struct {
	Name string
	Age  int
}

// WithName 返回设置姓名的选项。
func WithName(name string) optparams.Option[PersonOpt] {
	return optparams.NewFuncOption(func(o *PersonOpt) {
		o.Name = name
	})
}

// WithAge 返回设置年龄的选项。
func WithAge(age int) optparams.Option[PersonOpt] {
	return optparams.NewFuncOption(func(o *PersonOpt) {
		o.Age = age
	})
}

func main() {
	both := optparams.Combine(WithName("bob"), WithAge(25))
	opt := optparams.GetOption(&PersonOpt{}, both)
	fmt.Printf("%s(%d)\n", opt.Name, opt.Age)
}
Output:
bob(25)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL