Loading

Go语言精进之路读书笔记第25条——了解变长参数函数的妙用

25.1 什么是变长参数

变长参数函数:调用时可以接受零个、一个或多个实际参数的函数。

func Println(a ...interface{}) (n int, err error)
  • 只能有一个“...T”类型形式参数,且该形式参数应该为函数参数列表中的最后一个形式参数。
  • “...T”类型形式参数在函数内呈现为[]T类型的变量
  • 在函数外部,“...T”类型形式参数可匹配和接受的实参类型有两种(二者不能混用):
    • 多个T类型变量;
    • t...(t为[]T类型变量)
func sum(args ...int) int {
    var total int

    for _, v := range args {
        total += v
    }

    return total
}

func main() {
    a, b, c := 1, 2, 3
    println(sum(a, b, c))
    nums := []int{4, 5, 6}
    println(sum(nums...))
}

容易出现实参与形参不匹配的问题

  • []string类型变量不能直接赋值给[]interface{}类型变量
func dump(args ...interface{}) {
    for _, v := range args {
        fmt.Println(v)
    }
}

func main() {
    //s := []string{"Tony", "John", "Jim"}
    s := []interface{}{"Tony", "John", "Jim"}
    dump(s...)
}
  • 不过append函数例外
func foo(b ...byte) {
    fmt.Println(string(b))
}

func main() {
    b := []byte{}
    b = append(b, "hello"...)
    fmt.Println(string(b))

    foo("hello"...)
}

25.2 模拟函数重载

Go语言不允许在同一个作用域下定义名字相同但函数原型不同的函数

要重载的函数的参数,类型相同/不同,参数的个数的变化的,可以通过变长参数函数结合interface{}类型来实现

25.3 模拟实现函数的可选参数与默认参数

如果参数在传入时有隐式要求的固定顺序,可以利用变长参数函数模拟实现。局限性:调用者只能从右侧的参数开始逐一进行省略传递的处理。

25.4 实现功能选项模式

Rob Pike的博文“自引用函数与选项设计”,功能选项(functional option)模式
好处:

  • 不随时间变化的公共API
  • 参数可读性更好
  • 配置选项高度可扩展
  • 提供使用默认选项的最简单方式
  • 使用更安全(调用者无法修改options)
type FinishedHouse struct {
    style                  int    // 0: Chinese, 1: American, 2: European
    centralAirConditioning bool   // true or false
    floorMaterial          string // "ground-tile" or ”wood"
    wallMaterial           string // "latex" or "paper" or "diatom-mud"
}

type Option func(*FinishedHouse)

func NewFinishedHouse(options ...Option) *FinishedHouse {
    h := &FinishedHouse{
        // default options
        style:                  0,
        centralAirConditioning: true,
        floorMaterial:          "wood",
        wallMaterial:           "paper",
    }

    for _, option := range options {
        option(h)
    }

    return h
}

func WithStyle(style int) Option {
    return func(h *FinishedHouse) {
        h.style = style
    }
}

func WithFloorMaterial(material string) Option {
    return func(h *FinishedHouse) {
        h.floorMaterial = material
    }
}

func WithWallMaterial(material string) Option {
    return func(h *FinishedHouse) {
        h.wallMaterial = material
    }
}

func WithCentralAirConditioning(centralAirConditioning bool) Option {
    return func(h *FinishedHouse) {
        h.centralAirConditioning = centralAirConditioning
    }
}

func main() {
    fmt.Printf("%+v\n", NewFinishedHouse()) // use default options
    fmt.Printf("%+v\n", NewFinishedHouse(WithStyle(1),
        WithFloorMaterial("ground-tile"),
        WithCentralAirConditioning(false)))
}
posted @ 2024-02-13 16:14  brynchen  阅读(8)  评论(0编辑  收藏  举报