go语言函数变参

例子

函数变参的定义:
func Printf(format string, a ...interface{}) (n int, err error) { ... }

调用方式
Printf("%s-%d-%s", "AAA", 123, "BBB")

传递方式

在函数调用的时候,caller会把所有的变参转换成一个slice对象,然后传递给callee,

package main

import "fmt"
import "reflect"

func foo1(args ...string) {
    fmt.Println("=====foo1()====")
    fmt.Println("Type=", reflect.TypeOf(args))
    fmt.Println("Value=", reflect.ValueOf(args))
    fmt.Println(args)
}

func main() {
    foo1("aaa", "bbb", "ccc")
}

运行结果为:

$ go build && ./main     
=====foo1()====
Type= []string
Value= [aaa bbb ccc]
[aaa bbb ccc]

可以很清楚的看到在foo1函数内,args的类型是[]string是一个slice.

main函数内容可以这么写,能产生同样的结果:

func main() {
    //foo1("aaa", "bbb", "ccc")
    params := []string{"aaa", "bbb", "ccc"}
    foo1(params...) // notice: not foo1(params)
}

如何变参传递给其他变参函数

这里我们讨论的是如何传递变参给另一个变参函数,如果对象不是一个变参函数,那么调用者可以分析slice得到每一个元素,这样就随便处理了。

把变参作为整体传给另一个变参函数也很容易,使用"args..."就行,例如上述代码再调用fmt.Printf

package main

import "fmt"
import _ "reflect"

func foo1(args ...interface{}) {
    fmt.Printf("%s-%s-%s", args...)
}

func main() {
    foo1("aaa", "bbb", "ccc")
}

运行结果

$ go build && ./main 
aaa-bbb-ccc

如果没有使用args...,而是直接使用了args会出什么结果呢?

package main

import "fmt"
import _ "reflect"

func foo1(args ...interface{}) {
    fmt.Printf("%s-%s-%s", args)
}

func main() {
    foo1("aaa", "bbb", "ccc")
}

运行结果:

$ go build && ./main 
[aaa bbb ccc]-%!s(MISSING)-%!s(MISSING)

这里因为"%s-%s-%s",需要三个string类型来匹配,而args作为整体只能算是提供了第一个参数。所以导致
第一个%s <- args, 即[]string {"aaa", "bbb", "ccc"}
第二个%s <- 没有值
第三个%s <- 没有值

常用场景

这个需求经常被用在自定义log输出的场合。比如

func myInfo(formating string, args ...interface{}) {
  // fmt.Printf(fInfoormating+"\n", args...)
  fmt.Printf("INFO: %s", fmt.Sprintf(formatting, args...))
}

func myDebug(formating string, args ...interface{}) {
  // fmt.Printf(fInfoormating+"\n", args...)
  fmt.Printf("DEBUG: %s", fmt.Sprintf(formatting, args...))
}

调用者

myInfo("Hello World");
myDebug("This is the %d bug", 12)
myDebug("This %s are %d", "AAA", 20)

你可能感兴趣的:(go语言函数变参)