Анонимные функции в Go

GolangGolangBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В предыдущих лабораторных работах вы узнали, как писать и использовать именованные функции, как организовать код в модули и как повысить читаемость кода, разделяя логику на отдельные функции. В этой лабораторной работе мы рассмотрим анонимные функции (anonymous functions) — особый тип функций, у которых нет имени. Анонимные функции полезны, когда вы хотите определить небольшой кусок логики «на месте», не объявляя отдельную именованную функцию. Они особенно полезны для коротких, самодостаточных операций или когда вам нужно передать функцию в качестве аргумента другой функции (например, в колбэках). Используя анонимные функции, вы можете писать более компактный и выразительный код.

Основные темы:

  • Что такое анонимные функции и как их определять
  • Зачем и когда использовать анонимные функции
  • Вызов анонимных функций без присвоения им имени
  • Передача параметров анонимным функциям и возврат значений
  • Использование анонимных функций в качестве колбэк-функций для более гибкого кода

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("Golang")) -.-> go/BasicsGroup(["Basics"]) go(("Golang")) -.-> go/FunctionsandControlFlowGroup(["Functions and Control Flow"]) go/BasicsGroup -.-> go/values("Values") go/BasicsGroup -.-> go/variables("Variables") go/FunctionsandControlFlowGroup -.-> go/functions("Functions") go/FunctionsandControlFlowGroup -.-> go/closures("Closures") subgraph Lab Skills go/values -.-> lab-149099{{"Анонимные функции в Go"}} go/variables -.-> lab-149099{{"Анонимные функции в Go"}} go/functions -.-> lab-149099{{"Анонимные функции в Go"}} go/closures -.-> lab-149099{{"Анонимные функции в Go"}} end

Понимание анонимных функций

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

Синтаксис анонимной функции:

func(input parameters)(return parameters) {
    // code block
}

Это похоже на определение обычной функции, но без имени функции.

Сравним его с объявлением обычной функции:

// Regular function declaration
func functionName(parameters...)(return values...) {
    code block
}

Зачем использовать анонимные функции?

  • Краткость: Они позволяют определить небольшие кусочки логики без создания отдельной именованной функции, делая код более компактным.
  • Локальная область видимости: Область видимости анонимных функций находится внутри окружающей функции, таким образом ограничивая загрязнение пространства имен.
  • Гибкость: Они могут быть переданы в качестве аргументов другим функциям или определены и выполнены сразу.

Когда использовать анонимные функции?

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

Создание анонимной функции без параметров

Начнем с простого примера, который выводит "hello world" с использованием анонимной функции. Сначала создайте файл с именем anonymous.go в директории проекта:

cd ~/project
touch anonymous.go

Откройте файл anonymous.go и добавьте следующий код:

package main

import "fmt"

func main() {
    // Define an anonymous function and assign it to a variable f
    f := func() {
        fmt.Println("hello world")
    }

    // Call the anonymous function via the variable f
    f()
}

Запустите программу:

go run anonymous.go

Ожидаемый вывод:

hello world

Здесь мы определили анонимную функцию с использованием синтаксиса func() {... }. Эта функция не принимает никаких параметров и не возвращает никаких значений. Мы присвоили эту анонимную функцию переменной f. Затем мы вызываем функцию с помощью f(). Это выполняет анонимную функцию и выводит "hello world".

Использование параметров в анонимных функциях

Анонимные функции могут принимать параметры, как и обычные функции. Изменим наш код, чтобы передать строку в качестве параметра.

Замените содержимое файла anonymous.go на следующее:

package main

import "fmt"

func main() {
    f := func(s string) {
        fmt.Println(s)
    }
    f("hello world")
}

Запустите программу:

go run anonymous.go

Ожидаемый вывод:

hello world

На этот раз наша анонимная функция принимает строковый параметр s. Часть func(s string) определяет, что анонимная функция принимает параметр с именем s типа строка. Когда мы вызываем f("hello world"), строка "hello world" передается в функцию, которая затем выводит ее в консоль. Это демонстрирует, как можно передавать значения в анонимные функции, чтобы сделать их более универсальными.

Возвращение значений из анонимных функций

Анонимные функции также могут возвращать значения. Создадим анонимную функцию, которая принимает два целых числа в качестве параметров и возвращает их сумму.

Замените содержимое файла anonymous.go на следующее:

package main

import "fmt"

func main() {
    f := func(a, b int) int {
        return a + b
    }
    result := f(3, 5)
    fmt.Println(result)
}

Запустите программу:

go run anonymous.go

Ожидаемый вывод:

8

Теперь сигнатура анонимной функции имеет вид func(a, b int) int. Это означает, что она принимает два целых числа (a и b) в качестве входных данных и возвращает целое число в качестве выходных данных. Тело функции return a + b вычисляет и возвращает их сумму. Когда мы вызываем f(3, 5), выполняется анонимная функция с аргументами 3 и 5, и возвращается результат 8. Затем мы сохраняем этот результат в переменной result и выводим его в консоль.

Объявление и немедленный вызов анонимных функций

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

Обновите файл anonymous.go:

package main

import "fmt"

func main() {
    res := func(a, b int) int {
        return a + b
    }(3, 5) // Call the anonymous function directly here
    fmt.Println(res)
}

Запустите программу:

go run anonymous.go

Ожидаемый вывод:

8

Здесь мы определили анонимную функцию func(a, b int) int { return a + b } и сразу же вызвали ее, добавив (3, 5) после объявления функции. Этот синтаксис func(...) {...}(...) позволяет определить и вызвать функцию в одном выражении. Аргументы в скобках передаются функции сразу. В этом случае функция возвращает сумму 3 и 5, которая затем присваивается переменной res. Это распространенная практика для простых, немедленно выполняемых функций и полезно для инициализации или коротких вычислений.

Использование анонимных функций в качестве функций обратного вызова (callback functions)

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

Что такое функции обратного вызова?

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

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

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

Замените содержимое файла anonymous.go следующим кодом:

package main

import (
    "fmt"
    "math"
)

// 'visit' takes a slice and a function. It applies the function to each element in the slice.
func visit(lst []float64, f func(float64)) {
    for _, value := range lst {
        f(value)
    }
}

func main() {
    arr := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}

    // Use an anonymous function to sum each element with itself
    visit(arr, func(v float64) {
        fmt.Printf("Sum:%.0f ", v+v)
    })
    fmt.Println()

    // Use an anonymous function to multiply each element by itself
    visit(arr, func(v float64) {
        fmt.Printf("Product:%.0f ", v*v)
    })
    fmt.Println()

    // Use an anonymous function to square each element using math.Pow
    visit(arr, func(v float64) {
        v = math.Pow(v, 2)
        fmt.Printf("Square:%.0f ", v)
    })
    fmt.Println()
}

Запустите программу:

go run anonymous.go

Ожидаемый вывод:

Sum:2 Sum:4 Sum:6 Sum:8 Sum:10 Sum:12 Sum:14 Sum:16 Sum:18
Product:1 Product:4 Product:9 Product:16 Product:25 Product:36 Product:49 Product:64 Product:81
Square:1 Square:4 Square:9 Square:16 Square:25 Square:36 Square:49 Square:64 Square:81

В этой программе мы сначала создаем функцию visit, которая принимает срез (lst) типа float64 и функцию (f) типа func(float64). Функция visit проходит по срезу и вызывает предоставленную функцию f для каждого элемента. Этот шаблон проектирования позволяет функции visit выполнять различную логику в зависимости от предоставленной функции обратного вызова f.

Внутри функции main мы вызываем функцию visit три раза с разными анонимными функциями, чтобы продемонстрировать, как функции обратного вызова обеспечивают гибкость.

  • Первая анонимная функция вычисляет сумму каждого элемента с самим собой.
  • Вторая анонимная функция вычисляет произведение каждого элемента на самого себя.
  • Третья анонимная функция возводит каждый элемент в квадрат с использованием функции math.Pow.

Это показывает, как анонимную функцию можно передать в качестве функции обратного вызова и как функция visit может выполнять разные действия на основе функции обратного вызова, переданной в качестве параметра. Это делает ваш код более переиспользуемым и модульным.

Итог

В этом практическом занятии вы узнали о анонимных функциях в языке Go. Анонимные функции не имеют имени и часто используются для коротких, одноразовых блоков логики. Они могут:

  • Быть присвоены переменным и вызываться позже.
  • Принимать параметры и возвращать значения.
  • Быть определены и вызваны сразу.
  • Использоваться в качестве функций обратного вызова (callback), когда передаются в качестве аргументов другим функциям, обеспечивая высокую гибкость и настраиваемость поведения.

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