小唯快跑啊
为了详细说明我的评论,Effective Go提到访问映射键的多值分配称为“逗号确定”模式。有时您需要将缺失的条目与零值区分开来。是否有“UTC”条目,或者是空字符串,因为它根本不在地图中?你可以用多重赋值的形式来区分。var seconds intvar ok boolseconds, ok = timeZone[tz]出于显而易见的原因,这被称为“逗号确定”习语。在这个例子中,如果 tz 存在,秒将被适当地设置并且 ok 为真;如果没有,秒将被设置为零,确定将是假的。操场证明这个我们可以看到这与调用常规函数不同,在常规函数中编译器会告诉您出现问题:package mainimport "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”的源代码为我们提供了几个可以查看的地方,包括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.//其关键在于此方法似乎可以确定某事是否实际上是“逗号正常”情况。挖掘到这个方法告诉我们,它会检查,看是否操作数的模式索引地图或者模式设置为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作为参数传递。搜索库的其余部分使我们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())由于在执行多值赋值时我们似乎只能使用“逗号确定”模式来获取两个返回值,因此这似乎是正确的地方!在上面的代码中,检查了左边的长度,当unpack被调用时,allowCommaOk参数是l == 2 && !returnPos.IsValid(). 将!returnPos.IsValid()在一定程度上混淆这里作为这将意味着,位置没有相关的文件或行信息与它,但我们会就忽略这个问题。在该方法中,我们有:var x operandif 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在除inassignment.go的Checker.initVars()方法之外的任何地方都采用硬编码为 false的参数,我们可以假设您在进行赋值时只会得到两个值,并且在左侧有两个变量。该unpack方法将通过检查您是否正在索引切片、从通道中获取值或进行类型断言来确定您是否确实获得了ok返回值由于您只能ok在进行赋值时获取值,因此在您的特定情况下,您将始终需要使用变量