听着Stand by me 也不知道为啥就有感觉写了,开始写的时候都不知道取什么标题,本来是想记录一下在写rkgrpcwebproxy时候的一个方法,主要解决的是结构体默认参数的问题。有点类似类初始化的默认参数,但感觉又很不相同,这可能就是golang独特的东西吧。

其实还是代码比较能说明问题

先准备一个结构体,这里我用的是rkgrpcwebproxy里面的入口结构体

type GRPCWebEntry struct {
   Name        string `yaml:"name" json:"name"` #rk 注册的名称
   Enabled     bool   `yaml:"enabled" json:"enabled"` #是否使用的开关
   Description string `yaml:"description" json:"description"` #描述
   Type        string `yaml:"type" json:"type"` #rk 注册类型
   LoggerEntry *rkentry.LoggerEntry `json:"-" yaml:"-"` # 可选的 rk log实例
   GrpcEntry   *rkgrpc.GrpcEntry    `yaml:"-" json:"-"` # 可选的 rk grpc实例
   CertEntry   *rkentry.CertEntry   `json:"-" yaml:"-"` # 可选的 rk证书实例
   ServerAddress string `yaml:"serverAddress" json:"server_address"` #代理的gRPC服务地址 存在GrpcEntry的时候直接用实例的参数地址
   BindAddress   string `yaml:"bindAddress" json:"bind_address"` #代理绑定的IP 0.0.0.0 
   BindPort      int    `yaml:"bindPort" json:"bind_port"` #代理绑定端口 Port 8000
   MaxCallRecvMsgSize  int           `yaml:"maxCallRecvMsgSize" json:"max_call_recv_msg_size"` #最大接受数据的大小 默认4M
   AllowedOrigins      []string      `yaml:"allowedOrigins" json:"allowed_origins"` #允许访问域
   AllowedHeaders      []string      `yaml:"allowedHeaders" json:"allowed_headers"` #允许的表头
   Websockets          *Websockets   `yaml:"websockets" json:"websockets"`
   Debug               bool          `yaml:"debug" json:"debug"` #是否调试
   HttpMaxWriteTimeout time.Duration `yaml:"http_max_write_timeout" json:"http_max_write_timeout"` #http 最大写入时间
   HttpMaxReadTimeout  time.Duration `yaml:"http_max_read_timeout" json:"http_max_read_timeout"` #http 最大读取时间
}

这个结构体主要用途就是实例化 grpc web 代理,在注释中也能看出来,我们有很多的默认值和可选项,我开始学go的时候用的是New:

func NewGRPCWebEntry() *GRPCWebEntry {
	return &GRPCWebEntry{
		Debug: false, //默认值
	}
}

这种方法是可以添加默认值的,碰见的问题就是不灵活,如果要改会造成很多的问题,改造一下:

func NewGRPCWebEntry(opts ...interface{}) *GRPCWebEntry {
	entry := &GRPCWebEntry{
		Debug: false,
	}
	for i, opt := range opts {
		//在这里处理添加的参数
	}
	return entry
}

因为go是强类型的所以我们需要一个中间类型

func NewGRPCWebEntry(opts ...GRPCWebEntryOption) *GRPCWebEntry {
	entry := &GRPCWebEntry{
		Debug: false,
	}
	for i, opt := range opts {
		//在这里处理添加的参数
	}
	return entry
}


type GRPCWebEntryOption func(*GRPCWebEntry)

最后就是水到渠成了

func NewGRPCWebEntry(opts ...GRPCWebEntryOption) *GRPCWebEntry {
	entry := &GRPCWebEntry{
		Debug: false, //默认调试为false
	}
	for i := range opts {
		opts[i](entry)
	}
	return entry
}

type GRPCWebEntryOption func(*GRPCWebEntry)

//修改调试模式
func WithDebug(debug bool) GRPCWebEntryOption {
	return func(entry *GRPCWebEntry) {
		entry.Debug = debug
	}
}

测试一下默认效果

func main() {
	entry := NewGRPCWebEntry()
	fmt.Println("entry debug", entry.Debug)
}
// Print : entry debug false

测试修改的效果

func main() {
	entry := NewGRPCWebEntry(WithDebug(true))
	fmt.Println("entry debug", entry.Debug)
}
// Print : entry debug true

其他的参数也能参照WithDebug来修改,这样实现灵活修改默认值的效果。

对了,最后应该推荐一下rk这个开源的项目,看好的项目源码还是学习最好的方法!