package main
import (
"fmt"
)
type options struct {
a int64
b string
c map[int]string
}
func NewOption(opt ...ServerOption) *options {
r := new(options)
for _, o := range opt {
o(r)
}
return r
}
type ServerOption func(*options)
func WriteA(s int64) ServerOption {
return func(o *options) {
o.a = s
}
}
func WriteB(s string) ServerOption {
return func(o *options) {
o.b = s
}
}
func WriteC(s map[int]string) ServerOption {
return func(o *options) {
o.c = s
}
}
func main() {
opt1 := WriteA(int64(1))
opt2 := WriteB("test")
opt3 := WriteC(make(map[int]string,0))
op := NewOption(opt1, opt2, opt3)
fmt.Println(op.a, op.b, op.c)
}
如上,最近看 grpc 的源码,发现了里面一种高逼格的构造函数的写法,表示震惊,学到了新姿势。
非常好,go-micro 也是这种写法
这个高逼格是闭包吧 = = 。
這個所謂 “高逼格” 寫法,其實來自 Rob Pike 他老人家 2014 年寫的一篇博客:https://commandcenter.blogspot.hk/2014/01/self-referential-functions-and-design.html
學用人家發明的 Go 卻不看他老人家的博客。。。
这篇文章中也有写道,写扩展性好的代码:函数 这里循序渐进的写了怎样写一个扩展性好的函数,讲的挺不错的。
我好几个库,都是这么写的,也是看 Rob Pike 的那文章学到的。
https://github.com/fanpei91/ktable https://github.com/fanpei91/metawire https://github.com/fanpei91/godht https://github.com/fanpei91/krpcwire
这种写法好理解,但是优势在哪里?
这样那?
package main
import (
"fmt"
)
type options struct {
a int64
b string
c map[int]string
}
func (o *options) writeA(a int64) *options {
o.a = a
return o
}
func (o *options) writeB(b string) *options {
o.b = b
return o
}
func (o *options) writeC(c map[int]string) *options {
o.c = c
return o
}
func main() {
op := new(options)
op.writeA(int64(1)).writeB("test").writeC(make(map[int]string, 0))
fmt.Println(op.a, op.b, op.c)
}
我也想知道这样写有啥好处,看起来很不直观的样子
没看出来有什么优势,新增 option 时,调用 NewOption 者依然要修改调用的地方,加入新的 option。 缺点反倒有,引入了 ServerOption ,间接隔离了数据和修改数据的方法。 至少在绝大多数场景下,我认为 @ 向晚 提供的方法更好。
之前每日新闻里有推荐. 很多库都是这么写的. @ 向晚 的方法我看到 zap 也用到了这种方法
前面提到的那个。。。不就是最简单的 builder 模式吗= =。
这就是一种编程模式吧 和链式编程一样的
向晚提供的更像 go 代码,从 go 的焦点更容易理解,楼主的方式从 java/js 的角度更容易理解
就是常规写法,LZ 孤陋寡闻了
向晚的方法确实更优雅。但这种写法只适合在特定的场景使用,否则,我直接 new 一个出来在 option.a=xxx 这种方式更优雅。
其实就是是 golang 的其中一个特性,适合就好,因为用而用就不好了。
链式操作~~
楼主的写法好处是无论 options 内部结构发生什么变化,NewOption 函数都不用修改。向晚的方法并不是构造函数,如果 options 在其他包里就不能用了
灵活性带来的是性能降低,成员变量越多越明显,用的时候还是要根据实际情况的。能直接初始化就直接初始化。
感谢 楼主分享
可不可以把 writeA, writeB, writeC 继续用代码生成呢?
elasticSearch 包也是这样写的 一个构造参数太多 这样写比较爽 不需要在意参数位置
それは面白い投稿です。 私はあなたのブログに戻ってきます。 basketball games
什么时候写程序的, 也标题党了?.................
就是 golang 的基本写法, 什么时候变成高级了.................... golang 说实话, 在开发语言本身上, 即没有语法糖 ( 也有, 很少语法糖), 也没有高级写法, 更没有黑魔法, 可能说是即简单又无趣. golang 用时间长了, 时间精力都放在业务/算法上, 加上 golang 的 pprof 这类工具链完整而基本算是足够用, go 写的程序在测试/调优上也挺无趣: 花时间好好监测各指标前后变化, 找到优化点, 是可以预期的..........也算是无趣的一点.