go/ notesПРАКТИЧЕСКИЙ КОНСПЕКТДокументация Go ↗

ЯЗЫК GO · КОРОТКО И ПО ДЕЛУ

От первой строки
до работающей
программы.

Основные конструкции Go, небольшие примеры и команды, которые стоит держать под рукой.

Статическая типизацияКомпиляцияGoroutines
01

Быстрый старт

Установите Go с официальной страницы загрузки. Создайте каталог проекта и модуль: его путь станет основой импортов ваших пакетов.

ТЕРМИНАЛ
mkdir hello-go
cd hello-go
go mod init example.com/hello-go

Сохраните программу в main.go. Выполнение начинается с функции main в пакете main.

MAIN.GO
package main

import "fmt"

func main() {
    name := "Go"
    fmt.Printf("Hello, %s!\n", name)
}

Запустите go run . или соберите исполняемый файл командой go build ..

Подробнее: первая программа ↗
02

Типы и коллекции

Используйте := для объявления локальной переменной с выводом типа. Срез хранит последовательность элементов, а map — пары ключ–значение.

ВНУТРИ ФУНКЦИИ
name := "Ada"
age := 28
languages := []string{"Go", "SQL"}
languages = append(languages, "Rust")

scores := map[string]int{"Ada": 95}
score, ok := scores[name]
if ok {
    fmt.Println(name, age, score)
}
for i, language := range languages {
    fmt.Println(i, language)
}
Нулевые значения

Числа начинают с 0, строки — с "", bool — с false. В nil-map можно читать, но перед записью её нужно инициализировать.

Подробнее: типы и коллекции ↗
03

Функции и ошибки

Функция может вернуть несколько значений. Для ожидаемых ошибок принято возвращать значение типа error и явно обрабатывать его в вызывающем коде.

ФРАГМЕНТ · ИМПОРТ FMT
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("деление на ноль")
    }
    return a / b, nil
}

func printResult() {
    result, err := divide(12, 3)
    if err != nil {
        fmt.Println("Ошибка:", err)
        return
    }
    fmt.Println(result)
}

Добавляйте контекст через fmt.Errorf("read config: %w", err); проверяйте обёрнутые ошибки с помощью errors.Is и errors.As.

Подробнее: работа с ошибками ↗
04

Конкурентность

Ключевое слово go запускает функцию в отдельной goroutine. Каналы позволяют передавать значения и синхронизировать выполнение.

ВНУТРИ MAIN · ИМПОРТ FMT
result := make(chan int)

go func() {
    result <- 6 * 7
}()

fmt.Println(<-result) // 42
Учитывайте жизненный цикл

Goroutine не завершится автоматически при потере ссылки на неё. Для отмены длительных операций используйте context.Context, а доступ к общим данным синхронизируйте.

Подробнее: goroutines и каналы ↗
05

Тестирование

Тесты размещают в файлах с окончанием _test.go. Следующий тест проверяет функцию divide из предыдущего раздела.

MAIN_TEST.GO
package main

import "testing"

func TestDivide(t *testing.T) {
    got, err := divide(12, 3)
    if err != nil || got != 4 {
        t.Fatalf("divide(12, 3) = %v, %v; want 4, nil", got, err)
    }
    if _, err := divide(1, 0); err == nil {
        t.Fatal("expected an error for division by zero")
    }
}

Запуск: go test ./.... Для поиска гонок данных: go test -race ./... на поддерживаемой платформе.

Подробнее: первый тест ↗
06

Рабочий набор команд

go fmt ./...Отформатировать код
go vet ./...Проверить подозрительные конструкции
go mod tidyСогласовать зависимости модуля
go test ./...Запустить тесты
go build ./...Проверить сборку пакетов