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

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的源码,发现了里面一种高逼格的构造函数的写法,表示震惊,学到了新姿势。

已邀请:

这样那?

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)
}

h12 - https://h12.io/about

赞同来自: lwhile cholerae astaxie haoc7

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

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

yang11 - 初学者

赞同来自: lwhile zi marks_gui

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

sonx

赞同来自: xiaoma buscoop

向晚的方法确实更优雅。但这种写法只适合在特定的场景使用,否则,我直接new一个出来在option.a=xxx这种方式更优雅。

其实就是是golang的其中一个特性,适合就好,因为用而用就不好了。

stirlingx - https://github.com/liyue201

赞同来自: lwhile

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

touei

赞同来自: songtianyi

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

xianghanhuang

赞同来自: haoxiong

灵活性带来的是性能降低,成员变量越多越明显,用的时候还是要根据实际情况的。能直接初始化就直接初始化。

pathbox - https://pathbox.github.io/

赞同来自:

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

cholerae

赞同来自:

我也想知道这样写有啥好处,看起来很不直观的样子

bruceauyeung

赞同来自:

没看出来有什么优势,新增option时,调用NewOption者依然要修改调用的地方,加入新的option。 缺点反倒有,引入了 ServerOption ,间接隔离了数据和修改数据的方法。 至少在绝大多数场景下,我认为 @向晚 提供的方法更好。

hank

赞同来自:

之前每日新闻里有推荐. 很多库都是这么写的. @向晚 的方法我看到zap也用到了这种方法

zido

赞同来自:

前面提到的那个。。。不就是最简单的builder模式吗= =。

Mrwxj - 图样图森破

赞同来自:

这就是一种编程模式吧 和链式编程一样的

lvpengzhen

赞同来自:

向晚提供的更像go代码,从go的焦点更容易理解,楼主的方式从java/js的角度更容易理解

lichao2018

赞同来自:

就是常规写法,LZ孤陋寡闻了

touei

赞同来自:

链式操作~~

wuhan

赞同来自:

楼主的写法好处是无论options内部结构发生什么变化,NewOption函数都不用修改。向晚的方法并不是构造函数,如果options在其他包里就不能用了

freedbg

赞同来自:

感谢 楼主分享

leyafo - http://www.leyafo.com/

赞同来自:

可不可以把 writeA, writeB, writeC 继续用代码生成呢?

sakura

赞同来自:

elasticSearch 包也是这样写的 一个构造参数太多 这样写比较爽 不需要在意参数位置

要回复问题请先登录注册