Шаг 76.
Язык программирования Go.
Замыкания
На этом шаге рассмотрим замыкания в Go.
Замыкание – это функция, "захватывающая" константы и переменные, представленные в той же области видимости, где создается сама
функция, если она ссылается на них. Это означает, что замыкание
сохраняет возможность доступа к таким константам и переменным,
даже когда оно вызывается далеко от того места, где оно было создано. При этом не имеет значения, находятся ли захваченные константы и переменные в области видимости в точке вызова замыкания, – если замыкание ссылается на них, они будут храниться в
памяти для использования в замыкании.
В языке Go все анонимные функции (или литералы функций, как
они называются в спецификации языка Go) являются замыканиями.
Замыкания создаются практически так же, как и обычные функции, но с одним важным отличием: замыкания не имеют имен (то
есть за ключевым словом func сразу же следует открывающая круглая скобка). Чтобы иметь возможность пользоваться замыканиями,
они обычно присваиваются переменным или сохраняются в структурах данных (таких как отображения или срезы).
Анонимные функции в инструкциях defer или go являются замыканиями.
Одна из областей применения замыканий – создание функций-оберток , предопределяющих один или более аргументов обертываемой функции.
Задание 1. Написать функцию, которая ко множеству имен файлов добавляет различные расширения (рис.1):
Рис.1. Пример работы приложения
Раскрыть/скрыть решение и комментарии.
Требуется обернуть оператор + конкатенации строк так, чтобы один
операнд имел фиксированное значение (расширение), а другой (имя
файла) мог изменяться.
/*Переменные, addPng и addJpg, хранят ссылки на анонимные функции (то есть на
замыкания). Такие ссылки могут вызываться как обычные именованные функции*/
addPng := func(name string) string { return name + ".png" }
addJpg := func(name string) string { return name + ".jpg" }
for i := 1; i <= 10; i++ {
if i%2 == 0 {
fmt.Println(addJpg("filename" + strconv.Itoa(i)))
} else {
fmt.Println(addPng("filename" + strconv.Itoa(i)))
}
}
Архив примера можно взять здесь.
На практике, когда требуется создать множество похожих функций, вместо того чтобы создавать их по отдельности, часто используются фабричные функции, то есть функции, возвращающие
другие функции. Реализуем пример с использованием фабричной функции,
возвращающей функцию, которая добавляет указанное расширение к имени файла, но только если это расширение отсутствует в
имени файла.
/*Фабричная функция MakeAddSuffix() возвращает замыкание,
сохраняющее значение переменной suffix, имевшееся на момент создания замыкания.
Возвращаемое замыкание принимает один строковый аргумент (например, имя файла)
и возвращает строку, которая является именем файла с указанным расширением.*/
func Расширение(suffix string) func(string) string {
return func(name string) string {
if !strings.HasSuffix(name, suffix) {
return name + suffix
}
return name
}
}
addZip := Расширение(".zip")
addTgz := Расширение(".tar.gz")
fmt.Printf("%s\n%s\n%s\n", addTgz("имяФайла"), addZip("имяФайла"),
addZip("gobook.zip"))
Результат работы приложения показан на рис.2:
Рис.2. Пример работы приложения
Архив примера можно взять здесь.
На следующем шаге рассмотрим рекурсивные функции в Go.
Предыдущий шаг
Содержание
Следующий шаг