Какая разница между закрытием переменных и коротких переменных в Go?
Из моего чтения спецификации:
Краткое объявление переменной... является сокращением для регулярной переменной декларация с выражениями инициализатора, но без типов...
http://golang.org/ref/spec
Я бы подумал, что они были одинаковыми:
var f func()
f = func() {
...
}
и
f := func() {
...
}
Но похоже, что это не так. Я пытался обернуть саморекурсивную функцию внутри внешней функции, но это работает:
func myOuter() {
var f func()
f = func() {
f()
}
f()
}
Но это не означает, что undefined: f
во внутренней функции.
func myOuter() {
f := func() {
f()
}
f()
}
Так в чем же разница?
Есть ли способ написать это с помощью короткой декларации или мне нужно написать ее долго?
Ответы
Ответ 1
f := func() { /* ... */ }
идентичен var f func() = func() { /* ... */ }
(но только более поздний разрешен на уровне пакета). В вашем конкретном случае ни один из двух вариантов не будет работать, так как оператор будет оцениваться справа налево. Решение - как вы уже сказали, - разделить выражение на два. Один для объявления переменной и другой для назначения ему рекурсивной функции.
Ответ 2
Первые два примера кода семантически идентичны при одном условии: выражение, которое назначается вашей переменной, должно быть разрешено во время компиляции.
Это будет одинаково в любых обстоятельствах, кроме случаев, когда вы пытаетесь назначить выражение, которое ссылается на только что объявленную переменную (или функцию). Проблема здесь в том, что, поскольку golang анализируется правильно-ассоциативно, он попытается набрать решение с правой стороны, прежде чем назначать его влево. Если вы ссылаетесь на переменную слева от оператора объявления-назначения, вы ссылаетесь на переменную, которую компилятор еще не знает, следовательно, undefined: f
.
Другой пример, который даст похожие результаты:
x := x + 1
Хотя это гораздо менее распространено для людей, потому что более очевидно, что x еще не назначен.