Какая разница между закрытием переменных и коротких переменных в 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 еще не назначен.