Введение
Go (или Golang) — это современный язык программирования, разработанный в Google. Он сочетает в себе простоту и строгость синтаксиса, а также высокую производительность, сопоставимую с C и C++. Go часто используют для разработки высоконагруженных серверных приложений, сетевых сервисов, микросервисов и утилит.
Эта статья познакомит вас с основами языка Go: от структуры программы до работы с функциями, переменными, типами, константами и преобразованием данных.
Пакеты (Packages)
В Go все начинается с пакетов. Пакет — это совокупность файлов, объединённых по функциональности и логике.
Каждая программа на Go обязательно должна содержать пакет main, если это исполняемое приложение.
Входная точка программы — функция main, которая должна находиться в пакете main.
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("Моё любимое число —", rand.Intn(10))
}
В этом примере:
- package main говорит компилятору, что это основной исполняемый пакет.
- import (...) подключает внешние пакеты:
- fmt — для форматированного вывода (аналог printf).
- math/rand — для генерации случайных чисел.
- rand.Intn(10) генерирует случайное число от 0 до 9.
Правила:
- Имя пакета обычно совпадает с последним элементом пути импорта.
- Если вы пишете библиотеку, вы не используете package main, а называете пакет логично: package utils, package auth и т. д.
Импорты (Imports)
Импорты позволяют подключать пакеты (встроенные или сторонние) в вашу программу.
Существует 2 стиля импорта:
Группированный (факторизованный)
import (
"fmt"
"math"
)
По одному
import "fmt"
import "math"
Группированный стиль считается хорошим тоном и улучшает читаемость.
Как это работает?
При импорте Go ищет пакет в стандартной библиотеке, затем — в GOPATH или go.mod (если используется модулирование).
Если пакет не используется, программа не скомпилируется — Go требует чистоту кода.
Пример:
package main
import (
"fmt"
"math"
)
func main() {
fmt.Printf("Теперь у тебя %g проблем.\n", math.Sqrt(7))
}
Экспортируемые имена (Exported Names)
В Go доступ к функциям и переменным из другого пакета возможен только если имя начинается с заглавной буквы.
Пример:
import "math"
math.Pi // OK
math.pi // Ошибка — не экспортируется
Pi — экспортированная переменная (const).
pi — нет, так как она с маленькой буквы.
Go таким образом реализует инкапсуляцию: всё, что начинается с маленькой буквы — скрыто от внешнего мира.
Почему так?
Это упрощает доступ к публичному API и делает код чище: всё приватное — по умолчанию скрыто.
Функции (Functions)
Функции в Go объявляются с помощью ключевого слова func.
func add(x int, y int) int {
return x + y
}
- Имя: add
- Параметры: x и y типа int
- Возвращает: int
Если параметры одного типа идут подряд, тип указывается один раз:
func add(x, y int) int {...}
Вызов:
fmt.Println(add(42, 13)) // → 55
Множественные результаты (Multiple Results)
Go позволяет возвращать несколько значений из функции:
func swap(x, y string) (string, string) {
return y, x
}
a, b := swap("hello", "world") // a = "world", b = "hello"
Это удобно для:
- Возврата значений и ошибок: (value, error)
- Обмена значениями
- Быстрой обработки нескольких результатов
Именованные возвращаемые значения (Named Returns)
Вы можете задать имена возвращаемым значениям прямо в объявлении функции:
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // без аргументов — вернутся x и y
}
Здесь:
split - имя функции.
sum int - параметр, функция принимает одно целое число.
(x, y int) - именованные возвращаемые значения: функция вернёт два значения, оба типа int, и они уже имеют имена x и y.
Это значит, что внутри функции вы можете использовать x и y как обычные переменные, они уже "задекларированы".
Так как мы задали имена переменным в заголовке функции, компилятор знает, что именно их и нужно вернуть, и мы просто пишем return без всего. Это называется голый return (naked return).
Голый return рекомендуется использовать только в коротких функциях — в длинных это ухудшает читаемость. Например, в длинных функциях, через 20–30 строк кода может быть уже непонятно, какие значения возвращаются, и где они были заданы.
Вот как выглядит та же функция, но без именованных возвращаемых значений:
func split(sum int) (int, int) {
x := sum * 4 / 9
y := sum - x
return x, y // теперь нужно указать явно
}
Переменные (Variables)
Переменные объявляются с помощью ключевого слова var.
var i int
var name string
Можно объявить несколько переменных за раз:
var x, y int
var a, b = 1, "text"
Пример:
var c, python, java bool
func main() {
var i int
fmt.Println(i, c, python, java)
}
Инициализация переменных:
Переменные можно инициализировать при объявлении:
var i, j int = 1, 2
Go определеяет тип по значению, поэтому тип можно опустить:
var c, python, java = true, false, "нет!"
Краткое объявление переменных:
Внутри функций можно использовать :=, чтобы сразу объявить и инициализировать переменную:
name := "Go"
age := 15
Это эквивалентно var name string = "Go", но проще.
Важно:
:= можно использовать только внутри функций.
Базовые типы
Go поддерживает множество встроенных типов:
- Логический: bool
- Строковый: string
- Целые, Знаковые: int, int8, int16, int32, int64
- Целые, Беззнаковые: uint, uint8, uint16, uint32, uint64, uintptr
- Символы: byte (alias для uint8), rune (alias для int32)
- С плавающей точкой: float32, float64
- Комплексные: complex64, complex128
Пример:
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
Нулевые значения (Zero Values)
Если переменной не присвоено значение, она получает нулевое значение:
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s) //0 0 false ""
Преобразование типов
Go требует явного преобразования типов:
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
Или проще:
i := 42
f := float64(i)
u := uint(f)
Пример:
var x, y int = 3, 4
var f float64 = math.Sqrt(float64(x*x + y*y))
var z uint = uint(f)
fmt.Println(x, y, z)
Определение типа (Type inference)
Go умеет автоматически определять тип переменной на основе присваиваемого значения:
v := 42 // int
pi := 3.14 // float64
c := 1 + 2i // complex128
var i int
j := i // j — это int
Константы (Constants)
Константы объявляются с помощью const. Они могут быть:
- Числовыми
- Строковыми
- Булевыми
Константы нельзя инициализировать через :=.
const Pi = 3.14
const Greeting = "Привет"
const Truth = true
Числовые константы
Константы в Go обладают высокой точностью.
Например:
const (
Big = 1 << 100
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 { return x * 0.1 }
func main() {
fmt.Println(needInt(Small)) // OK
fmt.Println(needFloat(Big)) // OK
// fmt.Println(needInt(Big)) // Ошибка!
}
Разбор:
1 << 100 означает: сдвинуть число 1 влево на 100 битов.
Это то же самое, что записать единицу с 100 нулями после неё в двоичной системе — получается огромное число, значительно больше, чем помещается в обычный int64.
Пример:
1 << 3 = 8 // 1000 (в двоичной)
1 << 4 = 16 // 10000
1 << 100 = ... // Очень большое число (≈ 1.27 × 10^30)
Small = Big >> 99 — сдвигает Big вправо на 99 битов, т. е. делит его на 2^99.
Получается:
Small = (1 << 100) >> 99 = 1 << 1 = 2
Функции:
func needInt(x int) int {
return x*10 + 1
}
Принимает int, возвращает x * 10 + 1
Например: needInt(2) → 2*10 + 1 = 21
func needFloat(x float64) float64 {
return x * 0.1
}
Принимает float64, возвращает x * 0.1
main():
func main() {
fmt.Println(needInt(Small)) // OK
fmt.Println(needFloat(Small)) // OK
fmt.Println(needFloat(Big)) // OK
}
Подробнее:
needInt(Small)
Small = 2, он подходит для int, т.к. маленький.
→ needInt(2) → 21
needFloat(Small)
Small = 2, Go автоматически приводит 2 к float64
→ needFloat(2.0) → 0.2
needFloat(Big)
Big — огромное значение, но Go позволяет его использовать с float64
Так как Big — это нетипизированная константа, она не привязана к типу, пока не окажется в контексте (float64)
→ Go автоматически подбирает нужный тип (если он помещается в float64)
Что будет, если вызвать needInt(Big)?
Если в main() вы попробуете написать:
fmt.Println(needInt(Big))
Вы получите ошибку компиляции:
constant 1267650600228229401496703205376 overflows int
Почему?
Big слишком велик, чтобы быть представленным как int — тип int в Go ограничен (обычно 64 бита).
Go не делает автоматическое приведение из "бесконечно большой" константы к типу, если это приведёт к переполнению.
Ключевые выводы
- Константы в Go - Могут быть нетипизированными, с высокой точностью до использования.
- Сдвиг битов - Можно легко делать большие или маленькие числа, сдвигая 1.
- Автоматическое приведение - Константа без типа может подстроиться под int, float64 и др., если она помещается.
- Ошибки переполнения - Go откажется компилировать код, если вы передаёте огромное значение в тип с меньшей разрядностью (int).
Заключение
В этой статье мы подробно разобрали основы языка программирования Go, уделив внимание как синтаксису, так и ключевым концепциям, которые делают Go лаконичным, безопасным и удобным для разработки производительного кода.
Вот основные выводы из изученного:
Структура программы
- Все Go-программы состоят из пакетов.
- Точка входа — функция main в пакете main.
Импорты
- Пакеты подключаются через import, лучше использовать факторизованный (группированный) стиль.
- Неиспользуемые импорты вызывают ошибку компиляции — Go поощряет чистый код.
Экспорт и инкапсуляция
- Только имена, начинающиеся с заглавной буквы, экспортируются за пределы пакета.
- Это встроенный механизм инкапсуляции, аналог модификаторов доступа в других языках.
Функции
- Go поддерживает функции с несколькими возвращаемыми значениями и именованными результатами.
- Возврат нескольких значений активно используется, например, для обработки ошибок.
Работа с переменными
- Переменные объявляются через var или := (внутри функций).
- Go использует определение типов, упрощая объявления.
Типы
- Встроенные типы включают int, float64, bool, string, complex128 и другие.
- Нулевые значения переменных определены по умолчанию.
Константы и точность
- Константы в Go могут быть нетипизированными и иметь произвольно высокую точность.
- С помощью битовых сдвигов можно удобно оперировать числами.
- Go строго следит за преобразованием типов, предотвращая переполнения на этапе компиляции.