Function golang返回多值问题
我想知道为什么这是有效的go代码:Function golang返回多值问题,function,go,Function,Go,我想知道为什么这是有效的go代码: func FindUserInfo(id string) (Info, bool) { it, present := all[id] return it, present } 但事实并非如此 func FindUserInfo(id string) (Info, bool) { return all[id] } 有没有避免临时变量的方法?您可以使用命名返回保存两个按键: func FindUserInfo(id string) (i
func FindUserInfo(id string) (Info, bool) {
it, present := all[id]
return it, present
}
但事实并非如此
func FindUserInfo(id string) (Info, bool) {
return all[id]
}
有没有避免临时变量的方法?您可以使用命名返回保存两个按键:
func FindUserInfo(id string) (i Info, ok bool) {
i, ok = all[id]
return
}
但是除此之外,我不认为你想要什么是可能的。我不是专家,但我相信当你试图返回数组时,你会遇到编译时错误,即
返回所有[id]
。原因可能是函数返回类型被特别提到为(Info,bool)
,当您执行返回所有[id]
时,它无法将所有[id]
的返回类型映射到(Info,bool)
然而,在上述解决方案中,返回的变量
i
和ok
与函数(i Info,ok bool)
的返回类型中提到的变量相同,因此编译器知道它返回的是什么,而不是默认情况下只执行(i Info,ok bool)
,golang中的贴图在访问键时返回单个值
因此,return all[id]
不会为一个需要2个返回值的函数编译。为了详细说明my,提到访问映射键的多值赋值被称为“逗号ok”模式
有时,您需要区分缺少的条目和零值。是否有“UTC”的条目,或者该条目是空字符串,因为它根本不在地图中?你可以用多重赋值的形式来区分
出于显而易见的原因,这被称为“逗号ok”成语。在本例中,如果tz存在,秒将被适当设置,ok将为真;否则,秒将设置为零,ok将为false
我们可以看出,这与调用常规函数不同,在常规函数中,编译器会告诉您有问题:
package main
import "fmt"
func multiValueReturn() (int, int) {
return 0, 0
}
func main() {
fmt.Println(multiValueReturn)
asgn1, _ := multiValueReturn()
asgn2 := multiValueReturn()
}
在屏幕上,这将输出
# command-line-arguments
/tmp/sandbox592492597/main.go:14: multiple-value multiValueReturn() in single-value context
这给我们一个提示,它可能是编译器正在做的事情。因为“commaOk”给了我们一些可以看的地方,包括
在编写本文时,该方法的godoc如下所示:
// unpack takes a getter get and a number of operands n. If n == 1, unpack
// calls the incoming getter for the first operand. If that operand is
// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
// function call, or a comma-ok expression and allowCommaOk is set, the result
// is a new getter and operand count providing access to the function results,
// or comma-ok values, respectively. The third result value reports if it
// is indeed the comma-ok case. In all other cases, the incoming getter and
// operand count are returned unchanged, and the third result value is false.
//
// In other words, if there's exactly one operand that - after type-checking
// by calling get - stands for multiple operands, the resulting getter provides
// access to those operands instead.
//
// If the returned getter is called at most once for a given operand index i
// (including i == 0), that operand is guaranteed to cause only one call of
// the incoming getter with that i.
//
关键的一点是,这个方法似乎可以确定某个东西是否是“逗号ok”的情况
深入研究该方法告诉我们,它将检查操作数的模式是否是索引映射的或模式是否设置为commaok
(这确实为我们提供了许多关于何时使用它的提示,但在源代码中搜索commaok
的赋值,我们可以看到它何时和何时使用)。记住粗体字,以后再说
if x0.mode == mapindex || x0.mode == commaok {
// comma-ok value
if allowCommaOk {
a := [2]Type{x0.typ, Typ[UntypedBool]}
return func(x *operand, i int) {
x.mode = value
x.expr = x0.expr
x.typ = a[i]
}, 2, true
}
x0.mode = value
}
allowCommaOk
是函数的一个参数。查看该文件中调用unpack
的位置,我们可以看到所有调用方都将false
作为参数传递。搜索存储库的其余部分将导致我们找到工作分配。转到中的
因为在执行多值赋值时,我们似乎只能使用“逗号ok”模式来获取两个返回值,所以这似乎是一个正确的地方!在上述代码中,检查左侧的长度,当调用unpack
时,allowCommaOk
参数是l==2&&!returnPos.IsValid()
。!returnPos.IsValid()
在这里有点混乱,因为这意味着它的位置是正确的,但我们将忽略这一点
在这种方法下,我们得到:
var x operand
if commaOk {
var a [2]Type
for i := range a {
get(&x, i)
a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
}
check.recordCommaOkTypes(rhs[0], a)
return
}
那么这一切告诉我们什么呢?
- 由于
unpack
方法采用了一个allowCommaOk
参数,除了在assignment.go
的Checker.initVars()
方法中,该参数在任何地方都被硬编码为false,因此我们可以假设在执行赋值时只会得到两个值,并且在左侧有两个变量
unpack
方法将通过检查您是否正在索引切片、从通道获取值或执行类型断言来确定您是否确实得到了ok
值作为回报
- 由于在执行赋值时只能获得
ok
值,因此在您的特定情况下,似乎始终需要使用变量
简单地说:第二个示例之所以不是有效的Go代码,是因为语言规范这么说的
在两个变量的赋值中只产生一个次值。Return语句不是赋值
map[K]V类型映射上的索引表达式,用于特殊形式的赋值或初始化
v、 ok=a[x]
v、 确定:=a[x]
var v,ok=a[x]
生成一个额外的非类型化布尔值。如果映射中存在键x,则ok的值为true,否则为false
此外,为映射编制索引不是一个“”,这是从函数返回值的三种方法之一(第二种方法,其他两种方法在此不相关):
有三种方法可以从结果类型的函数返回值:
返回值可以在“return”语句中明确列出。每个表达式必须是单值的,并且可以赋值给函数结果类型的相应元素
“return”语句中的表达式列表可以是对多值函数的单个调用。其效果就好像从该函数返回的每个值都被分配给了一个临时变量,该临时变量具有相应的值的类型,然后是一个列出这些变量的“return”语句,在这一点上,前面案例的规则适用
如果函数的结果类型为其结果参数指定名称,则表达式列表可能为空。结果参数充当普通局部变量,函数可以根据需要为其赋值。“return”语句返回这些变量的值
至于你的实际问题:避免临时变量的唯一方法是使用
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
var x operand
if commaOk {
var a [2]Type
for i := range a {
get(&x, i)
a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
}
check.recordCommaOkTypes(rhs[0], a)
return
}