Модуль
1Основы функций← вы здесь2Variadic-функции3Замыкания4defer и panic/recover
Урок 1~12 минут

Основы функций

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

Базовый синтаксис:

go
func имя(параметры) тип_возврата {
    // тело
}

Пример — сложение двух чисел:

go
func add(a int, b int) int {
    return a + b
}

Если параметры одного типа — тип можно указать один раз:

go
func add(a, b int) int {
    return a + b
}

Несколько возвращаемых значений

Go умеет возвращать сразу несколько значений. Самый распространённый паттерн — результат + ошибка:

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...

Можно игнорировать ненужные значения с помощью _:

go
result, _ := divide(10, 2)

Именованные возвращаемые значения

Имена можно задать прямо в сигнатуре:

go
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 функции — это полноценные значения. Их можно:

  • присваивать переменным
  • передавать как аргументы
  • возвращать из других функций
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

Анонимная функция создаётся прямо в месте использования.


Тип функции

У каждой функции есть тип — сигнатура:

go
var fn func(int, int) int
fn = add           // add(a, b int) int — тип совпадает
fn = func(a, b int) int { return a - b } // тоже подходит

Это позволяет хранить коллекции функций:

go
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

Стек вызовов

Каждый вызов функции создаёт стековый фрейм — область памяти с локальными переменными и аргументами. При возврате фрейм уничтожается.

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

Go позволяет возвращать несколько значений из функции — это идиоматичный способ вернуть результат и ошибку одновременно.
func add(a, b int) int {
    return a + b
}

func main() {
    x := add(3, 4)
    fmt.Println(x)
}
GOROUTINE STACK ↑ растёт вверх
main()▶ ACTIVE
x=?
main() начинается

Новый фрейм main() создан в стеке горутины

1 / 4
🎯
Миссия 1 из 4
Как объявить функцию с двумя возвращаемыми значениями — int и error?