4

В документации к пакету нашел следующий код:

check:=func(err error) {
      if err != nill {
      log.Fatal(err)
      }
 }

Далее по коду происходит вызов:

check(err)

как это правильно называется и для чего так делают? Почему нельзя было просто создать обыкновенную функцию :

func check(err error) {
 if err != nil {
     log.Fatal(err)
     }
 }

и вызывать так же, как предыдущую

  • Я не знаю golang, но может быть вы угадали, и это lambda-функция? Хотя, как я посмотрел примеры функций на этом языке, везде этот подход используется при декорировании. Но, возможно, это просто примеры такие –  Apr 20 '17 at 01:54

2 Answers2

10

Это не анонимная функция и не замыкание. Это "функция как переменная" (function as value).

Почему нельзя было просто создать обыкновенную функцию?

Без контекста не ясно. Возможно переменная check переопределятся в момент выполнения.

Анонимная функция

Анонимная функция - функция, которая не может быть переопределена или вызвана повторно. Простыми словами, функция не имеет имени (анонимная) поэтому невозможно "назвать" или её повторно.

например:

I

callItAsCallback(data, func(response string) {
    print(response)
})

https://play.golang.org/p/Z8InpVJL9W

II

go func() {
    print("Hello!")
} ()

https://play.golang.org/p/6Q0ITEMbta

Функция как значение

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

var check func()
if time.Now().Second()%2 == 0 {
    check = func() {
        print("четное")
    }
} else {
    check = func() {
        print("нечетное")
    }
}

check()

Замыкание

Замыкание - функция, которая хранит данные из области видимости родительской функции. Это как "характер" функции, ее особенность.

Замыкания не возможны без функций "высшего порядка" (функции возвращающие другие функции). Исключение горутины.

I В этом примере замыкание исользовано для инкапсуляции приватных значений. Не очень полезно в go. https://play.golang.org/p/7_ES6AKjlI

II Класический пример примитивнейшей "фабрики"(паттерн проектирования).

package main

func main() {
    MakePizza("сыром!")()
    MakePizza("грибами!")()
}

func MakePizza(with string) func() {
    msg := "Пицца с "
    return func() {
        println(msg + with)
    }
}

Пицца с сыром!

Пицца с грибами!

https://play.golang.org/p/RuQV2b04nn

Та же фабрика, но без замыкания. Это функция высшего порядка возвращающая анонимную функцию. https://play.golang.org/p/YhAM0kYWba

III Ну и напоследок класический пример замыкания горутин в цикле.

!!!! Этот пример заведомо неправильный!

package main

import "time"

func main() {
     for i := 0; i < 10; i++ {
        go func() {
            println(i)
        }()
    }
    time.Sleep(time.Second)
}

10 10 10 10 10 10 10 10 10 10

https://play.golang.org/p/jfHE9mGCV4

Правильный вариант, но это уже обычная анонимная функция.

package main

import "time"

func main() {
     for i := 0; i < 10; i++ {
        go func(i int) {
            println(i)
        }(i)
    }
    time.Sleep(time.Second)
}

0 1 2 3 4 5 6 7 8 9

https://play.golang.org/p/lPFt-_HRY6

Заключение

Анонимные функции используются как callback(передаются как параметер в другую функцию) или как возвращаемое значение в функциях "высшего порядка".

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

Функция высшего порядка - функция возврщающая другие функции, как с замыканием так и без.

Замыкание - это эффект который может нести анонимная или "функция как значение" функция возвращаемая из функции высшего порядка или запущенная как горутина. Особенность в том, что функция может ссылаться на значения из родительской области видимости после "завершения" родительской функции.

insolor
  • 49,104
im7mortal
  • 146
  • Хм. А чем пример ТС не анонимная функция, присваиваемая переменной? – VladD May 22 '17 at 06:43
  • 1
    Идеальный ответ, очень понятно рассказал. – Nulliza Mar 23 '20 at 09:32
0

Все зависит от того как часто происходит вызов функции, возможно так автор пытался немного оптимизировать память. Если это огромный пакет, то возможно в этом есть смысл. Посмотри на пакет "encoding/json" там в процессе сериализации происходит составление кеша методов для каждого типа данных, что в дальнейшем ускоряет процесс кодирования / декодирования.