GO小知识 - 不定参数与切片

388 阅读2分钟

GO小知识 - 不定参数与切片

简述概念

1. 切片

切片是对数组的抽象, 是对数组一个连续片段的引用, 也可简单理解是是一个"长度可变的数组", 简单举几个例子

func main() {
    args := make([]string, 3)
    a[0] = "Hello"
    a[1] = "Go"
    a[2] = "World"
    
    // 或者简写 args := []string{"Hello", "Go", "World"}
    fmt.Printf("%#v", a) // []string{"Hello", "Go", "World"}
}

2. 不定参数

指函数传入的参数个数为不定数量, 最常见不定参数的函数就是 fmt.Sprintf, 我们看下源码

// Sprintf formats according to a format specifier and returns the resulting string.
func Sprintf(format string, a ...interface{}) string {
    p := newPrinter()
    p.doPrintf(format, a)     // 注意这行, 下面会讲
    s := string(p.buf)
    p.free()
    return s
}

使用区别

1. 不定参数转切片

不定参数在函数内可以直接当成切片使用, 例如刚才 fmt.Sprintf 里的一行: p.doPrintf(format, a), 我们看看这个参数源码

// doPrintln is like doPrint but always adds a space between arguments
// and a newline after the last argument.
func (p *pp) doPrintln(a []interface{}) {
	for argNum, arg := range a {
		if argNum > 0 {
			p.buf.writeByte(' ')
		}
		p.printArg(arg, 'v')
	}
	p.buf.writeByte('\n')
}

可以看到这里直接 fmt.Sprintf 里取值的 a 就是切片, 转而作为参数传往另一个函数, 我们自己写几个有意思例子

func main() {
    test("Hello", "Go", "World")
}

func test(a ...interface{}) {
    fmt.Printf("%#v", a) // []interface {}{"Hello", "Go", "World"}
}

func test(a ...string) {
    fmt.Printf("%#v", a) // []string{"Hello", "Go", "World"}
}

2. 打散切片

有时候我们希望把切片当成不定参数传参, 例如使用切片数据格式化打印, 这时候我们要用到语法糖 ... 打散切片

func main() {
    args := []string{"Hello", "Go", "World"}
    
    // fmt.Printf("%s, %s, %s", args...)  // 注意此写法因为类型问题, 会报错误 cannot use a (type []string) as type []interface {} in argument to fmt.Printf
    
    a := make([]interface{}, len(a))
    for i, v := range args {
            a[i] = v
    }
    fmt.Printf("%s %s %s", a...) // Hello Go World
}

总结

很简单的小知识, 主要认识不定参数与 ... 语法糖即可

如有错误或者疑问, 欢迎回复讨论

souyisou.png.png