Go с нуля: переменные, типы, функции и управление потоком

Почему Go

Go (Golang) — компилируемый язык от Google, 2009 год. Главные преимущества:

bash
go version  # go1.22.0
go run main.go   # запустить
go build -o app  # скомпилировать

Переменные

go
// Три способа объявить переменную
var x int = 10
var y = 20          // тип выводится
z := 30             // короткое объявление (только внутри функций)
 
// Несколько переменных
a, b := 1, 2
var (
    name string = "Go"
    version = 1.22
)

Нулевые значения (zero values) — Go инициализирует переменные автоматически:

Основные типы

go
// Целые числа
var i int     // платформозависимый (64-bit на 64-bit системе)
var i8 int8   // -128 ... 127
var i64 int64 // -9.2*10^18 ... 9.2*10^18
var u uint    // беззнаковый
 
// Числа с плавающей точкой
var f32 float32 // 6-7 значимых цифр
var f64 float64 // 15-16 значимых цифр (по умолчанию)
 
// Строки
var s string = "Hello, Go!"
len(s)        // 10 (байты, не символы!)
s[0]          // 72 (byte = uint8)
 
// Булево
var ok bool = true

Функции

go
// Базовая функция
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)
}
 
// Именованные возвращаемые значения
func minMax(nums []int) (min, max int) {
    min, max = nums[0], nums[0]
    for _, n := range nums {
        if n < min { min = n }
        if n > max { max = n }
    }
    return // bare return
}

Управление потоком

go
// if — без скобок вокруг условия
if x > 0 {
    fmt.Println("положительное")
} else if x < 0 {
    fmt.Println("отрицательное")
} else {
    fmt.Println("ноль")
}
 
// if с инициализацией
if err := doSomething(); err != nil {
    log.Fatal(err)
}
 
// switch — без break, fallthrough явный
switch day {
case "Mon", "Tue", "Wed", "Thu", "Fri":
    fmt.Println("рабочий")
case "Sat", "Sun":
    fmt.Println("выходной")
default:
    fmt.Println("неизвестно")
}
 
// for — единственный цикл в Go
for i := 0; i < 10; i++ { ... }  // классический
for i < 10 { ... }                // while-стиль
for { ... }                       // бесконечный
 
// range — итерация
nums := []int{1, 2, 3}
for i, v := range nums {
    fmt.Printf("%d: %d\n", i, v)
}
 
m := map[string]int{"a": 1}
for k, v := range m { ... }

Указатели

go
x := 42
p := &x       // адрес x
*p = 100      // изменить через указатель
fmt.Println(x) // 100
 
// В функциях — изменение оригинала
func double(n *int) {
    *n *= 2
}
double(&x)    // передать адрес

Go не имеет арифметики указателей (в отличие от C). Это намеренное ограничение для безопасности.

Коллекции

go
// Массив (фиксированный размер)
var arr [3]int = [3]int{1, 2, 3}
 
// Срез (slice) — динамический, используется повсеместно
s := []int{1, 2, 3}
s = append(s, 4, 5)
sub := s[1:3]     // [2, 3] — view, не копия!
 
// Map
m := map[string]int{"a": 1, "b": 2}
m["c"] = 3
val, ok := m["d"]   // ok = false если нет ключа
delete(m, "a")

Структуры

go
type User struct {
    Name  string
    Email string
    Age   int
}
 
u := User{Name: "Alice", Email: "alice@example.com", Age: 30}
u.Age = 31
 
// Методы
func (u User) Greet() string {
    return "Привет, " + u.Name
}
 
// Pointer receiver — изменяет оригинал
func (u *User) Birthday() {
    u.Age++
}

Интерфейсы

go
type Stringer interface {
    String() string
}
 
// Любой тип с методом String() реализует Stringer
func (u User) String() string {
    return fmt.Sprintf("%s (%d)", u.Name, u.Age)
}
 
// Неявная реализация — не нужен explicit implements
var s Stringer = User{Name: "Bob", Age: 25}
fmt.Println(s.String())

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

go
// Горутина — лёгкий поток (2KB стек, vs 1MB для OS потока)
go func() {
    fmt.Println("параллельно")
}()
 
// Канал — коммуникация между горутинами
ch := make(chan int)
go func() { ch <- 42 }()
val := <-ch  // блокирует до получения
 
// WaitGroup — ждать завершения горутин
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(n int) {
        defer wg.Done()
        fmt.Println(n)
    }(i)
}
wg.Wait()

Обработка ошибок

go
// Ошибки — обычные значения, не исключения
f, err := os.Open("file.txt")
if err != nil {
    return fmt.Errorf("не удалось открыть: %w", err)
}
defer f.Close()
 
// %w — wrapping для errors.Is/As
var pathErr *os.PathError
if errors.As(err, &pathErr) {
    fmt.Println("путь:", pathErr.Path)
}

Отличие от Python/JS

GoPythonJavaScript
ТипизацияСтатическаяДинамическаяДинамическая
КомпиляцияКомпилируемыйИнтерпретируемыйJIT
КонкурентностьГорутиныasyncio/threadsPromises/workers
Скорость~C~10-100x медленнее~5-10x медленнее
null safetynil, но строгоNonenull/undefined

Go проще C++ и быстрее Python. Отличный выбор для серверных приложений, CLI-инструментов и систем с высокой нагрузкой.

Интерактивные уроки по теме
Hello, World!+60 XP →Переменные в Go+100 XP →Целые числа+100 XP →Строки и руны+110 XP →float64 и числа с плавающей точкой+110 XP →if, switch, for+120 XP →bool и логические операторы+90 XP →Константы и iota+100 XP →Пакет fmt: форматирование вывода+110 XP →
Готов учиться интерактивно?

Двигай слайдеры и наблюдай как работает математика

Начать учиться →