Типы данных в Go
Go — статически типизированный язык, что означает, что тип каждой переменной известен на этапе компиляции. Это помогает предотвратить множество ошибок и делает код более предсказуемым.
1. Базовые типы (Primitive Types)
Логический тип (bool)
Самый простой тип. Может принимать только два значения: true (истина) или false (ложь).
- Частота использования: Постоянно.
- Когда использовать: Для хранения состояний, флагов, результатов сравнений и в условных конструкциях (
if,for).
var isLoggedIn bool = true
var hasAccess bool = false
if isLoggedIn && !hasAccess {
fmt.Println("Пользователь вошел, но доступ запрещен.")
}
Целочисленные типы (int, uint, int8 и т.д.)
Предназначены для хранения целых чисел. Делятся на знаковые (int) и беззнаковые (uint).
- Частота использования:
int: Постоянно. Это тип по умолчанию для целых чисел.int64,uint32и др.: По ситуации. Используются, когда важен точный размер (например, для баз данных, сетевых протоколов) или для экономии памяти в больших структурах.
- Правило по умолчанию: Всегда используйте
int, если нет веской причины выбрать другой тип.
// Самый распространенный случай
var counter int = 10
// Когда нужно гарантировать 64-битность (например, для ID из БД)
var userID int64 = 1234567890
// Когда значение не может быть отрицательным и невелико
var age uint8 = 25
Числа с плавающей точкой (float32, float64)
Предназначены для хранения вещественных чисел (с дробной частью).
-
float32: 32-битное число, меньшая точность. -
float64: 64-битное число, двойная точность. -
Частота использования:
float64: Часто.float32: Редко. Используется в основном для экономии памяти, например, в 3D-графике.
-
Правило по умолчанию: Всегда используйте
float64для избежания проблем с точностью.
// Рекомендуемый тип для вещественных чисел
var price float64 = 199.99
// Менее точный тип
var temperature float32 = 36.6
Комплексные числа (complex64, complex128)
Предназначены для математических вычислений с мнимой частью. complex64 состоит из двух float32, а complex128 — из двух float64.
- Частота использования: Крайне редко.
- Когда использовать: В узкоспециализированных областях, таких как научные расчеты, обработка сигналов, физика. 99% разработчиков никогда не используют их в коммерческой разработке.
var c complex128 = complex(5, 2) // 5 + 2i
fmt.Println(c)
Строки (string)
Представляют собой последовательность байтов. В Go строки неизменяемы (immutable). Это означает, что после создания строки изменить ее содержимое нельзя, можно только создать новую.
- Частота использования: Постоянно.
- Когда использовать: Для хранения любого текста.
var name string = "Alice"
greeting := "Hello, " + name // Создается новая строка
// Строки неизменяемы
// greeting[0] = 'h' // Ошибка компиляции!
Важно:
len(str)возвращает количество байт, а не символов. Для корректной работы с Unicode-символами используйтеrune.
2. Составные типы (Composite Types)
Эти типы строятся на основе базовых и других составных типов.
Массивы ([n]T)
Коллекция элементов одного типа с фиксированной длиной. Размер массива является частью его типа, поэтому [5]int и [10]int — это два разных типа.
- Частота использования: Редко.
- Почему редко? Фиксированный размер делает их негибкими. Почти всегда вместо них используются слайсы.
- Когда использовать: Когда вам нужно гарантировать, что коллекция имеет строго определённый размер (например, для хранения RGB-цвета
[3]uint8).
var primaryColors [3]string
primaryColors[0] = "Red"
primaryColors[1] = "Green"
primaryColors[2] = "Blue"
// primaryColors[3] = "Yellow" // Ошибка: выход за пределы массива
Слайсы ([]T)
Гибкое и мощное представление последовательности элементов. Слайс — это "вид" или "окно" в базовый массив. Он имеет динамическую длину.
- Частота использования: Постоянно. Это самый распространенный способ работы с коллекциями в Go.
- Когда использовать: Практически всегда, когда вам нужна последовательность элементов.
// Создание слайса
var numbers []int // nil-слайс
scores := []int{10, 20, 30}
names := make([]string, 0, 10) // Длина 0, емкость 10
// Добавление элементов
scores = append(scores, 40) // scores теперь [10, 20, 30, 40]
Карты (map[K]V)
Неупорядоченная коллекция пар "ключ-значение". Все ключи должны быть одного типа, а все значения — другого.
- Частота использования: Постоянно.
- Когда использовать: Для хранения данных, которые удобно получать по уникальному ключу (ассоциативные массивы, хэш-таблицы, словари).
// Телефонная книга: ключ - string, значение - int
phonebook := make(map[string]int)
phonebook["Alice"] = 12345
phonebook["Bob"] = 67890
// Получение значения
bobsNumber, ok := phonebook["Bob"]
if ok {
fmt.Printf("Номер Боба: %d\n", bobsNumber)
}
Структуры (struct)
Композитный тип, который позволяет сгруппировать поля разных типов в единое целое. Это аналог классов (без методов) в других языках.
- Частота использования: Постоянно.
- Когда использовать: Для моделирования сущностей реального мира (пользователь, продукт, заказ) и создания собственных сложных типов данных.
type User struct {
ID int
Name string
IsActive bool
}
func main() {
user1 := User{
ID: 1,
Name: "John Doe",
IsActive: true,
}
fmt.Printf("Пользователь: %s (ID: %d)\n", user1.Name, user1.ID)
}
3. Ссылочные и специальные типы
Указатели (*T)
Переменная, которая хранит адрес в памяти другой переменной.
- Частота использования: Часто.
- Когда использовать:
- Чтобы разрешить функции изменять переданное ей значение.
- Чтобы избежать копирования больших структур при передаче в функцию (повышает производительность).
func deactivateUser(u *User) {
u.IsActive = false // Изменяем оригинальную структуру по указателю
}
func main() {
user1 := User{ID: 1, Name: "John", IsActive: true}
deactivateUser(&user1) // Передаем адрес переменной user1
fmt.Println(user1.IsActive) // Вывод: false
}
Интерфейсы (interface)
Тип, который определяет набор методов. Любой тип, который реализует все методы интерфейса, неявно удовлетворяет этому интерфейсу.
- Частота использования: Постоянно. Это основа полиморфизма в Go.
- Когда использовать: Для написания гибкого, слабо связанного кода, который работает с поведением, а не с конкретными типами.
// Интерфейс определяет поведение "умеет издавать звук"
type Speaker interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string { return "Woof!" }
type Cat struct{}
func (c Cat) Speak() string { return "Meow!" }
// Эта функция работает с любым типом, который удовлетворяет Speaker
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
MakeSound(Dog{}) // Woof!
MakeSound(Cat{}) // Meow!
}