如何将多个 return 值传递给可变参数函数?

How to pass multiple return values to a variadic function?

我有一个 Go 函数,它 returns 两个整数值。下面是函数

func temp() (int, int){
 return 1,1
}

是否可以将 temp 函数直接放入 Println 并使用如下字符串格式打印两个输出:

fmt.Println("first= %d and second = %d", temp() ) // This doesn't work

在 Python 中,我可以执行以下操作:

def func():
    return 1,1
print("{0}={1}".format(*func())
>> '1=2'

我也可以在 Go 中做类似的事情吗?

不,这是不可能的。您必须将多值表达式中的所有值分配给单独的变量才能使用它们,例如:

a, b := temp()
fmt.Println("first = %d and second = %d", a, b)
// first = 1 and second = 1

[编辑]

有趣的是,在某些情况下,如果参数类型和元数匹配,或者对于纯可变参数函数,您似乎可以使用多值表达式作为函数调用参数 (Go Playground):

func oneTwo() (int, int) {
  return 1, 2
}

func incr2(x, y int) (int, int) {
  return x + 1, y + 1
}

func main() {
  incr2(oneTwo()) // OK: multi-value return and arguments match.

  fmt.Println(oneTwo()) // OK: pure variadic function.

  fmt.Printf("%d %d", oneTwo()) // ERR: mixed formal and variadic args.
}

当我没有使用如下任何字符串格式时,我能够打印它

fmt.Println(temp())

只有 Println 支持,printf

不支持

前言: 我在 github.com/icza/gox, see gox.Wrap().

发布了这个实用程序

首先,对于您尝试执行的操作,您应该使用 fmt.Printf() instead of fmt.Println(),因为只有前者期望并使用格式字符串。

今后,默认情况下不支持此功能,因为引用自 Spec: Calls:

As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order. The call of f must contain no parameters other than the call of g, and g must have at least one return value. If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.

并且 fmt.Printf() 的签名为:

func Printf(format string, a ...interface{}) (n int, err error)

除了函数调用(调用的 return 值)之外,您不能将其他参数传递给 fmt.Printf()

注意fmt.Println()的签名是:

func Println(a ...interface{}) (n int, err error)

这意味着 fmt.Println(temp()) 有效,任何其他至少具有一个 return 值的函数也是如此,因为引用部分的最后一句允许这样做 ( “如果 f 有一个最终的 ... 参数,它会被分配 g 的 return 值,这些值在分配常规参数后仍然存在。”)

但是通过一些小技巧我们也可以用 fmt.Printf() 实现你想要的。

请注意,如果 temp() 将 return 类型为 []interface{} 的值,我们可以使用 ... 将其作为某些可变参数的值传递。

意思是这个有效:

func main() {
    fmt.Printf("1: %v, 2: %v\n", temp()...)
}

func temp() []interface{} { return []interface{}{1, 2} }

并正确打印(在 Go Playground 上尝试):

1: 1, 2: 2

所以我们只需要一个效用函数将任何函数的 return 值包装到 []interface{} 中,这样我们就可以用它传递给 fmt.Printf().

而且非常简单:

func wrap(vs ...interface{}) []interface{} {
    return vs
}

如上所述(使用 fmt.Println()),我们可以将至少具有 1 个 return 值的任何函数的 return 值传递给 wrap() 作为值它的输入参数。

现在使用这个wrap()函数,看下面的例子:

func main() {
    fmt.Printf("1: %v\n", wrap(oneInt())...)
    fmt.Printf("1: %v, 2: %v\n", wrap(twoInts())...)
    fmt.Printf("1: %v, 2: %v, 3: %v\n", wrap(threeStrings())...)
}

func oneInt() int { return 1 }

func twoInts() (int, int) { return 1, 2 }

func threeStrings() (string, string, string) { return "1", "2", "3" }

这有效,并输出(在 Go Playground 上尝试):

1: 1
1: 1, 2: 2
1: 1, 2: 2, 3: 3

有关该主题的更多信息,请参阅相关问题: