Чтобы уточнить мой комментарий, Effective Go упоминает, что присваивание нескольких значений при доступе к ключу карты называется шаблоном "запятая ок".
Иногда вам нужно отличить отсутствующую запись от нулевого значения. Есть ли запись для «UTC» или это пустая строка, потому что ее вообще нет на карте? Вы можете различать форму множественного присвоения.
var seconds int
var ok bool
seconds, ok = timeZone[tz]
По понятным причинам это называется идиомой «запятая ок». В этом примере, если присутствует tz, секунды будут установлены соответствующим образом, а ok будет истинным; если нет, секунды будут установлены на ноль, а ok будет ложным.
Игровая площадка, демонстрирующая это
Мы видим, что это отличается от вызова обычной функции, когда компилятор сообщает вам, что что-то не так:
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" в исходном коде дает нам несколько мест для поиска, в том числе 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())
Поскольку кажется, что мы можем использовать только шаблон «запятая 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
, для которого жестко задано значение false везде, кроме метода Checker.initVars()
assignment.go
, мы, вероятно, можем предположить, что вы когда-либо получите только два значения при выполнении присваивания и две переменные слева. сторона руки.
- Метод
unpack
определяет, действительно ли вы действительно получаете взамен значение ok
, проверяя, индексируете ли вы срез, извлекаете ли значение из канала или выполняете утверждение типа.
- Поскольку вы можете получить значение
ok
только при выполнении задания, похоже, что в вашем конкретном случае вам всегда нужно будет использовать переменные.
person
Lander
schedule
09.05.2015