如何将多个 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
有关该主题的更多信息,请参阅相关问题:
我有一个 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 methodf
, then the callf(g(parameters_of_g))
will invokef
after binding the return values ofg
to the parameters off
in order. The call off
must contain no parameters other than the call ofg
, andg
must have at least one return value. Iff
has a final...
parameter, it is assigned the return values ofg
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
有关该主题的更多信息,请参阅相关问题: