Основы функций
Объявление функции
Базовый синтаксис:
func имя(параметры) тип_возврата {
// тело
}Пример — сложение двух чисел:
func add(a int, b int) int {
return a + b
}Если параметры одного типа — тип можно указать один раз:
func add(a, b int) int {
return a + b
}Несколько возвращаемых значений
Go умеет возвращать сразу несколько значений. Самый распространённый паттерн — результат + ошибка:
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("деление на ноль")
}
return a / b, nil
}
result, err := divide(10, 3)
if err != nil {
log.Fatal(err)
}
fmt.Println(result) // 3.3333...Можно игнорировать ненужные значения с помощью _:
result, _ := divide(10, 2)Именованные возвращаемые значения
Имена можно задать прямо в сигнатуре:
func minMax(arr []int) (min, max int) {
min, max = arr[0], arr[0]
for _, v := range arr {
if v < min { min = v }
if v > max { max = v }
}
return // «голый» return — возвращает min и max
}return без аргументов («голый return») возвращает именованные переменные в их текущем состоянии. Используй это в коротких функциях — в длинных это снижает читаемость.
Функции как значения
В Go функции — это полноценные значения. Их можно:
- присваивать переменным
- передавать как аргументы
- возвращать из других функций
func apply(a, b int, op func(int, int) int) int {
return op(a, b)
}
result := apply(3, 4, func(a, b int) int { return a + b })
fmt.Println(result) // 7Анонимная функция создаётся прямо в месте использования.
Тип функции
У каждой функции есть тип — сигнатура:
var fn func(int, int) int
fn = add // add(a, b int) int — тип совпадает
fn = func(a, b int) int { return a - b } // тоже подходитЭто позволяет хранить коллекции функций:
ops := map[string]func(int, int) int{
"+": func(a, b int) int { return a + b },
"-": func(a, b int) int { return a - b },
"*": func(a, b int) int { return a * b },
}
fmt.Println(ops["*"](3, 4)) // 12Стек вызовов
Каждый вызов функции создаёт стековый фрейм — область памяти с локальными переменными и аргументами. При возврате фрейм уничтожается.
Интерактивная симуляция выше показывает, как фреймы добавляются и убираются при рекурсии — посмотри на анимацию стека.
Новый фрейм main() создан в стеке горутины