我想知道为什么这是有效的代码:
func FindUserInfo(id string) (Info, bool) {
it, present := all[id]
return it, present
}
Run Code Online (Sandbox Code Playgroud)
但事实并非如此
func FindUserInfo(id string) (Info, bool) {
return all[id]
}
Run Code Online (Sandbox Code Playgroud)
有没有办法避免临时变量?
Ain*_*r-G 14
您可以使用命名返回来保存几个击键:
func FindUserInfo(id string) (i Info, ok bool) {
i, ok = all[id]
return
}
Run Code Online (Sandbox Code Playgroud)
但除此之外,我不认为你想要什么是可能的.
Lan*_*der 14
为了详细说明我的评论,Effective Go提到访问地图密钥的多值分配称为"逗号确定"模式.
有时您需要将缺失的条目与零值区分开来.是否有"UTC"的条目,或者是空字符串,因为它根本不在地图中?您可以区分多种分配形式.
var seconds int
var ok bool
seconds, ok = timeZone[tz]
Run Code Online (Sandbox Code Playgroud)
由于显而易见的原因,这被称为"逗号确定"成语.在这个例子中,如果存在tz,则将适当地设置秒,并且ok将为真; 如果没有,秒将被设置为零,ok将为false.
我们可以看到这不同于调用常规函数,编译器会告诉你出错了:
package main
import "fmt"
func multiValueReturn() (int, int) {
return 0, 0
}
func main() {
fmt.Println(multiValueReturn)
asgn1, _ := multiValueReturn()
asgn2 := multiValueReturn()
}
Run Code Online (Sandbox Code Playgroud)
在操场上,这将输出
# command-line-arguments
/tmp/sandbox592492597/main.go:14: multiple-value multiValueReturn() in single-value context
Run Code Online (Sandbox Code Playgroud)
这给了我们一个提示,它可能是编译器正在做的事情.搜索 "commaOk" 的源代码为我们提供了一些地方,包括types.unpack
在撰写本文时,方法的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.
//
Run Code Online (Sandbox Code Playgroud)
这个关键点是这个方法似乎确定某事实际上是否是"逗号确定"的情况.
深入研究该方法告诉我们,它将检查操作数的模式是否正在为一个映射建立索引,或者模式是否设置为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
}
Run Code Online (Sandbox Code Playgroud)
allowCommaOk是函数的参数.检查unpack该文件中调用的位置,我们可以看到所有调用者都false作为参数传递.搜索存储库的其余部分会引导我们进入assignments.go该Checker.initVars()方法.
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
Run Code Online (Sandbox Code Playgroud)
因为在进行多值赋值时,我们似乎只能使用"逗号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
}
Run Code Online (Sandbox Code Playgroud)
那么所有这一切告诉我们什么呢?
unpack方法采用的allowCommaOk是硬编码真实假无处不参数除了在assignment.go的Checker.initVars()方法,我们或许可以假设,做一个任务,当你将只获得两个值,并且对左侧的两个变量.unpack方法将通过检查您是否正在为切片编制索引,从通道获取值或执行类型断言来确定您是否确实获得了ok值.ok在执行赋值时获取值,因此在您的特定情况下,您始终需要使用变量简单地说:你的第二个例子无效的原因Go代码是因为语言规范是这样说的.;)
索引地图仅在两个变量的赋值中产生二次值.退货声明不是作业.
在特殊形式的赋值或初始化中使用的类型map [K] V的映射a上的索引表达式
v,ok = a [x]
v,ok:= a [x]
var v,ok = a [x]产生一个额外的无类型布尔值.如果键x存在于映射中,则ok的值为true,否则为false.
此外,索引映射不是" 对多值函数的单次调用 ",这是从函数返回值的三种方法之一(第二种,其他两种在这里不相关):
有三种方法可以从具有结果类型的函数返回值:
返回值可以在"return"语句中明确列出.每个表达式必须是单值的,并且可以赋值给函数结果类型的相应元素.
"return"语句中的表达式列表可以是对多值函数的单个调用.效果就好像从该函数返回的每个值都分配给具有相应值类型的临时变量,然后是列出这些变量的"return"语句,此时前一个案例的规则适用.
如果函数的结果类型指定其结果参数的名称,则表达式列表可以为空.结果参数充当普通局部变量,并且函数可以根据需要为它们分配值."return"语句返回这些变量的值.
至于你的实际问题:避免临时变量的唯一方法是使用非临时变量,但通常这是非常不明智的 - 即使在安全的情况下也可能没有太大的优化.
那么,为什么语言规范不允许在返回语句中使用这种特殊的地图索引(或类型断言或通道接收,两者都可以利用"逗号ok"成语)?这是个好问题.我的猜测:保持语言规范简单.