Подтвердить что ты не робот

Зачем добавлять "()" после закрытия тела в Голанге?

Я читаю The Go Programming Language Specifications и обнаружил, что не понимаю по-настоящему с помощью "()" после тела закрытия:

В Function literals:

func (ch chan int) {ch < - ACK} (replyChan) `

В Defer statements примере:

// f returns 1
func f() (result int) {
    defer func() {
        result++
    }() // why and how?
    return 0
}

Я не знаю о причине добавления и использования "()" после закрытия тела, надеюсь, кто-то может это объяснить.

4b9b3361

Ответ 1

Нельзя добавить () после (только) закрытия в defer. Спецификации языка для выражения defer определяют, что его "выражение" всегда должно быть вызовом функции.

И почему это так? Это то же самое, что и с любой другой функцией, в "defer" или нет:

Рассмотрим:

func f() int { return 42 }

и

a := f

против

b := f()

Первое выражение RHS - это значение функции. Во второй версии RHS - это значение, возвращаемое функцией - т.е. Вызов функции.

Итак, семантика:

defer f

против

defer f()

за исключением того, что первая версия не имеет смысла в контексте "defer", и поэтому в спецификациях упоминается, что она должна быть второй формой (только).

Это ИМХО также легче учиться из-за ортогональности с вышеописанным вызовом функции за пределами оператора defer.

Также обратите внимание, что вызов функции не только fn-expr, но и (), но список выражений обычно находится внутри скобки (включая пустой список). Там есть большая разница между:

for i := range whatever {
        defer func() { fmt. Println(i) }()
}

и

for i := range whatever {
        defer func(n int) { fmt. Println(n) }(i)
}

Первая версия печатает значение "i" в момент завершения замыкания, вторая печатает значение "i" в момент выполнения оператора депертирования.

Ответ 2

Ссылки

Спецификация языка программирования Go

Типы функций

Тип функции обозначает набор всех функций с одинаковыми параметры и типы результатов.

FunctionType   = "func" Signature .
Signature      = Parameters [ Result ] .
Result         = Parameters | Type .
Parameters     = "(" [ ParameterList [ "," ] ] ")" .
ParameterList  = ParameterDecl { "," ParameterDecl } .
ParameterDecl  = [ IdentifierList ] [ "..." ] Type .

Объявление функций

Объявление функции связывает идентификатор, имя функции, с функция.

FunctionDecl = "func" FunctionName Signature [ Body ] .
FunctionName = identifier .
Body         = Block .

Функциональные литералы

Функциональный литерал представляет анонимную функцию. Он состоит из спецификация типа функции и тела функции.

FunctionLit = FunctionType Body .

Функциональные литералы - это замыкания: они могут ссылаться на переменные, определенные в окружающая функция. Затем эти переменные распределяются между окружающая функция и функция literal, и они выживают как поскольку они доступны.

Функциональный литерал может быть назначен переменной или вызван напрямую.

Calls

Учитывая выражение f типа функции f,

f(a1, a2, … an)

вызывает f с аргументами a1, a2, … an.

В вызове функции значение функции и аргументы вычисляются в обычный порядок. После их оценки параметры вызова передаются по значению функции, и вызываемая функция начинается выполнение. Возвращаемые параметры функции передаются по значению Возврат к вызывающей функции при возврате функции.

Отложить заявления

Оператор "defer" вызывает функцию, выполнение которой отложено до момента возвращения окружающей функции.

DeferStmt = "defer" Expression .

Выражение должно быть вызовом функции или метода. Каждый раз, когда Выполняется инструкция defer ", значение функции и параметры для вызов оцениваются как обычно и сохраняются заново, но фактическая функция не вызывается. Вместо этого отложенные вызовы выполняются в порядке LIFO непосредственно перед возвратом окружающей функции, после возвращения значения, если таковые имеются, были оценены, но до того, как они будут возвращены вызывающего абонента.

Поскольку вы все еще запутались, вот еще одна попытка дать ответ на ваш вопрос.

В контексте вашего вопроса () - это оператор вызова функции.

Например, литерал функции

func(i int) int { return 42 * i }

представляет анонимную функцию.

Функциональный литерал, за которым следует оператор вызова ()

func(i int) int { return 42 * i }(7)

представляет анонимную функцию, которая затем вызывается непосредственно.

Обычно в вызове функции значение функции и аргументы вычисляются в обычном порядке. После их оценки параметры вызова передаются по значению функции, и вызываемая функция начинает выполнение. Возвращаемые параметры функции передаются по значению обратно вызывающей функции при возврате функции.

Однако вызов функции через оператор defer является частным случаем. Каждый раз, когда выполняется оператор "defer", значение функции и параметры для вызова оцениваются как обычные и сохраняются заново, но фактическая функция не вызывается. Вместо этого отложенные вызовы выполняются в порядке LIFO непосредственно перед тем, как возвращается окружающая функция, после того, как были возвращены возвращаемые значения, если они есть, но до того, как они будут возвращены вызывающему.

Выражение оператора defer должно быть вызовом функции или метода, который вызывается напрямую, а не только литералом функции или метода, который не вызывается напрямую. Таким образом, перед литералом функции или метода должен следовать оператор вызова (), так что выражение оператора деперса является вызовом функции или метода.

Оператор defer

defer func(i int) int { return 42 * i }(7)

.

Оператор defer

defer func(i int) int { return 42 * i }

неверно: syntax error: argument to go/defer must be function call.

Ответ 3

Если вы не хотите читать длинные ответы:

str := "Alice"
go func(name string) {
    fmt.Println("Your name is", name)
}(str)

То же, что и:

str := "Alice"
f := func(name string) {
    fmt.Println("Your name is", name)
}
go f(str)

Ответ 4

Без() вы не выполняете функцию.