8

我有一个返回两个整数值的 Go 函数。下面是函数

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

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

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 中做类似的事情吗?

4

3 回答 3

8

前言:我在 中发布了这个实用程序github.com/icza/gox,请参阅gox.Wrap()


首先,对于您尝试做的事情,您应该使用fmt.Printf()而不是fmt.Println()仅像前者所期望的那样使用格式字符串。

展望未来,默认情况下不支持此功能,因为引用Spec: Calls:

作为一种特殊情况,如果一个函数或方法的返回值g数量相等并且可以单独分配给另一个函数或方法的参数f,则调用f(g(parameters_of_g))f在将返回值按顺序绑定g到参数后调用。的调用不能包含除 的调用以外的任何参数,并且必须至少有一个返回值。如果有最终参数,则为其分配常规参数分配后剩余的返回值。ffggf...g

fmt.Printf()有以下签名:

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

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

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

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

这意味着它fmt.Println(temp())可以工作,任何其他至少有一个返回值的函数也是如此,因为引用部分的最后一句话允许这样做(“如果f有一个最终...参数,则g在分配常规参数。”

但是通过一个小技巧,我们也可以实现您想要的fmt.Printf()

请注意,如果temp()将返回一个 type 的值[]interface{},我们可以使用...它作为一些可变参数的值传递。

这意味着这有效:

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

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

它可以正确打印(在Go Playground上尝试):

1: 1, 2: 2

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

这非常简单:

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

如上所述(使用fmt.Println()),我们可以将具有至少 1 个返回值的任何函数的返回值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

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

单值上下文中的多个值

在普通函数上返回像 Golang 中的 'ok' 之类的映射

于 2018-10-04T20:49:42.630 回答
6

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

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

[编辑]

有趣的是,在某些情况下,如果参数类型和 arity 匹配,或者对于纯可变参数函数(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.
}
于 2018-10-04T19:44:05.560 回答
0

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

fmt.Println(temp())

这仅由 支持Println,但不支持printf

于 2018-10-04T20:38:06.090 回答