新手问题 发现一个高逼格的golang“构造函数”写法

SaltySailor · 2017年12月20日 · 最后由 tsingson 回复于 2019年09月17日 · 343 次阅读
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 的源码,发现了里面一种高逼格的构造函数的写法,表示震惊,学到了新姿势。

更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio

非常好,go-micro 也是这种写法

这个高逼格是闭包吧 = = 。

這個所謂 “高逼格” 寫法,其實來自 Rob Pike 他老人家 2014 年寫的一篇博客:https://commandcenter.blogspot.hk/2014/01/self-referential-functions-and-design.html

學用人家發明的 Go 卻不看他老人家的博客。。。

这篇文章中也有写道,写扩展性好的代码:函数 这里循序渐进的写了怎样写一个扩展性好的函数,讲的挺不错的。

这种写法好理解,但是优势在哪里?

这样那?

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 写的程序在测试/调优上也挺无趣: 花时间好好监测各指标前后变化, 找到优化点, 是可以预期的..........也算是无趣的一点.

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册