Go с нуля: переменные, типы, функции и управление потоком
Почему Go
Go (Golang) — компилируемый язык от Google, 2009 год. Главные преимущества:
- Компилируется в нативный бинарник (~10-50ms на большой проект)
- Встроенная конкурентность (горутины)
- Простой синтаксис, читаемый код
- Строгая статическая типизация
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 инициализирует переменные автоматически:
int→0float64→0.0string→""bool→false- указатели, интерфейсы, срезы →
nil
Основные типы
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
| Go | Python | JavaScript | |
|---|---|---|---|
| Типизация | Статическая | Динамическая | Динамическая |
| Компиляция | Компилируемый | Интерпретируемый | JIT |
| Конкурентность | Горутины | asyncio/threads | Promises/workers |
| Скорость | ~C | ~10-100x медленнее | ~5-10x медленнее |
| null safety | nil, но строго | None | null/undefined |
Go проще C++ и быстрее Python. Отличный выбор для серверных приложений, CLI-инструментов и систем с высокой нагрузкой.
Интерактивные уроки по теме