Какие существуют встроенные типы данных в Go?
Встроенные типы данных в Go
В Go типы можно разделить на несколько основных категорий: логические, числовые, строковые, составные и специальные.
1. Логический тип
bool
Хранит одно из двух значений: true или false.
var isActive bool = true
var isReady bool = falseНулевое значение типа bool — false.
2. Числовые типы
Целые числа со знаком
Могут хранить положительные, отрицательные числа и ноль.
| Тип | Размер | Диапазон |
|---|---|---|
int8 | 1 байт | от -128 до 127 |
int16 | 2 байта | от -32 768 до 32 767 |
int32 | 4 байта | примерно от -2,1 млрд до 2,1 млрд |
int64 | 8 байт | примерно от -9,2 × 10¹⁸ до 9,2 × 10¹⁸ |
int | 4 или 8 байт | зависит от платформы и реализации |
var age int = 30
var bigNumber int64 = 9_000_000_000int обычно имеет размер 32 бита на 32-битных системах и 64 бита на 64-битных системах.
При этом int и int64 остаются разными типами, даже если занимают одинаковое количество памяти:
var a int = 10
var b int64 = int64(a)Без явного преобразования присвоить int в int64 нельзя.
Целые числа без знака
Хранят только положительные числа и ноль.
| Тип | Размер | Диапазон |
|---|---|---|
uint8 | 1 байт | от 0 до 255 |
uint16 | 2 байта | от 0 до 65 535 |
uint32 | 4 байта | от 0 до примерно 4,2 млрд |
uint64 | 8 байт | от 0 до примерно 1,8 × 10¹⁹ |
uint | 4 или 8 байт | зависит от платформы |
uintptr | размер указателя | используется для низкоуровневой работы с адресами |
var count uint = 100
var port uint16 = 8080uintptr не следует использовать как обычный указатель. Он нужен в основном для взаимодействия с низкоуровневым кодом и пакетом unsafe.
Числа с плавающей точкой
Используются для хранения дробных чисел.
| Тип | Размер | Примерная точность |
|---|---|---|
float32 | 4 байта | около 7 значащих цифр |
float64 | 8 байт | около 15–16 значащих цифр |
var price float64 = 19.99
var pi float32 = 3.14159Такие числа хранятся приблизительно в виде:
знак × значащая часть × 2^экспонентаИз-за двоичного формата многие десятичные дроби нельзя представить абсолютно точно.
a := 0.1
b := 0.2
fmt.Println(a + b) // 0.30000000000000004
fmt.Println(a+b == 0.3) // falseДля денежных значений лучше использовать:
- целые числа, например количество копеек;
- специализированные decimal-библиотеки.
priceInCents := 1999Комплексные числа
Комплексное число состоит из действительной и мнимой частей.
| Тип | Части числа |
|---|---|
complex64 | две части типа float32 |
complex128 | две части типа float64 |
var c1 complex64 = 1 + 2i
var c2 complex128 = 3 + 4iИспользуются в основном в математических и научных расчётах.
3. Строки и типы для работы с текстом
string
string — неизменяемая последовательность байтов.
var name string = "Привет"Строка может содержать любые байты. При работе с текстом обычно используется кодировка UTF-8, но Go не требует, чтобы каждая строка обязательно содержала корректный UTF-8.
Функция len возвращает количество байтов, а не количество символов:
name := "Привет"
fmt.Println(len(name)) // 12Каждая русская буква в UTF-8 занимает два байта.
Строки неизменяемы: нельзя заменить отдельный байт строки.
s := "hello"
// s[0] = 'H' // ошибка компиляции
s = "Hello"При обращении по индексу возвращается байт:
s := "Hello"
fmt.Println(s[0]) // 72
fmt.Println(string(s[0])) // Hbyte
byte — псевдоним для uint8.
Используется для работы с отдельными байтами, файлами, сетевыми данными и ASCII-символами.
var b byte = 'A'
fmt.Println(b) // 65
fmt.Println(string(b)) // Arune
rune — псевдоним для int32.
Обычно представляет одну кодовую точку Unicode.
var r rune = 'Я'
fmt.Println(r) // 1071
fmt.Println(string(r)) // ЯВажно: rune не всегда равна одному визуальному символу. Некоторые отображаемые символы могут состоять из нескольких кодовых точек Unicode.
Для перебора строки по rune используется range:
for index, r := range "Привет" {
fmt.Println(index, r, string(r))
}4. Составные типы
Массив
Массив хранит фиксированное количество элементов одного типа.
var nums [3]int = [3]int{10, 20, 30}
nums[0] = 5Размер массива является частью его типа:
var a [3]int
var b [4]int[3]int и [4]int — разные типы.
Массивы в Go копируются при присваивании:
a := [3]int{1, 2, 3}
b := a
b[0] = 100
fmt.Println(a) // [1 2 3]
fmt.Println(b) // [100 2 3]Слайс
Слайс описывает участок базового массива.
Он хранит:
- ссылку на данные;
- длину;
- ёмкость.
nums := []int{1, 2, 3}
nums = append(nums, 4)Слайс не имеет фиксированного размера:
fmt.Println(len(nums)) // длина
fmt.Println(cap(nums)) // ёмкостьappend может использовать существующий базовый массив или создать новый, если текущей ёмкости недостаточно.
nums := make([]int, 0, 3)
nums = append(nums, 10)
nums = append(nums, 20)Мапа
Мапа хранит пары «ключ — значение».
ages := map[string]int{
"Alice": 30,
"Bob": 25,
}
fmt.Println(ages["Alice"]) // 30Получение значения по ключу:
age, exists := ages["Alice"]
if exists {
fmt.Println(age)
}Ключом мапы может быть только сравнимый тип.
Допустимые ключи:
map[string]int{}
map[int]string{}
map[[2]int]string{}Недопустимые ключи:
// map[[]int]string{} // ошибка
// map[map[string]int]int{} // ошибка
// map[func()]string{} // ошибкаСлайсы, мапы и функции нельзя использовать как ключи.
Структура
Структура объединяет несколько именованных полей в один тип.
type User struct {
Name string
Age int
}
u := User{
Name: "Иван",
Age: 25,
}Для именованного типа на основе структуры можно объявлять методы:
func (u User) Greeting() string {
return "Hello, " + u.Name
}Использование:
fmt.Println(u.Greeting())5. Указатели и функциональные типы
Указатель
Указатель хранит адрес другого значения в памяти.
x := 10
p := &xОператор & возвращает адрес значения:
p := &xОператор * получает значение по адресу:
fmt.Println(*p) // 10Через указатель можно изменить исходное значение:
*p = 20
fmt.Println(x) // 20Нулевое значение указателя — nil.
var p *int
fmt.Println(p == nil) // trueФункция
Функции в Go являются значениями.
Их можно:
- присваивать переменным;
- передавать в другие функции;
- возвращать из функций.
add := func(a, b int) int {
return a + b
}
fmt.Println(add(2, 3)) // 5Можно объявить собственный тип функции:
type Operation func(int, int) intvar op Operation = add6. Каналы
chan
Канал используется для передачи данных между горутинами.
Горутина — лёгкая функция, которая может выполняться одновременно с другими функциями.
ch := make(chan int)
go func() {
ch <- 42
}()
value := <-ch
fmt.Println(value) // 42Тип канала определяет, какие данные через него можно передавать:
chan int
chan string
chan UserКаналы могут быть:
chan int // двунаправленный канал
chan<- int // только для отправки
<-chan int // только для получения7. Интерфейсы
interface
Интерфейс описывает набор методов.
type Stringer interface {
String() string
}Тип автоматически удовлетворяет интерфейсу, если у него есть все необходимые методы.
type User struct {
Name string
}
func (u User) String() string {
return u.Name
}Теперь User удовлетворяет интерфейсу Stringer.
var s Stringer = User{Name: "Alice"}Явно указывать, что тип реализует интерфейс, не требуется.
any
any — псевдоним для пустого интерфейса:
interface{}Он может хранить значение любого типа.
var value any
value = 42
value = "hello"
value = trueЧтобы получить конкретный тип, используется проверка типа:
text, ok := value.(string)
if ok {
fmt.Println(text)
}8. Встроенный интерфейс error
error используется для представления ошибок.
Он объявлен примерно так:
type error interface {
Error() string
}Пример:
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}Использование:
result, err := divide(10, 0)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result)9. Псевдонимы и специальные значения
| Имя | Значение |
|---|---|
byte | псевдоним uint8 |
rune | псевдоним int32 |
any | псевдоним interface{} |
error | встроенный интерфейс для ошибок |
nil | отсутствие значения для некоторых типов |
true | булева константа |
false | булева константа |
nil может быть значением для:
- указателей;
- слайсов;
- мап;
- каналов;
- функций;
- интерфейсов.
var pointer *int
var slice []int
var users map[string]int
var ch chan int
var handler func()
var value anyВсе эти переменные изначально имеют значение nil.
10. Нулевые значения
Если переменная объявлена без начального значения, Go автоматически присваивает ей нулевое значение соответствующего типа.
var i int
var f float64
var b bool
var s string
var p *intЗначения:
i == 0
f == 0.0
b == false
s == ""
p == nilДля составных типов:
var arr [3]int
var slice []int
var users map[string]int
var user UserНулевые значения:
arr == [0 0 0]
slice == nil
users == nilВсе поля структуры также получают нулевые значения своих типов.
Важно: нулевая мапа равна nil. Из неё можно читать, но в неё нельзя записывать.
var users map[string]int
fmt.Println(users["Alice"]) // 0
// users["Alice"] = 30 // panicПеред записью мапу нужно создать:
users = make(map[string]int)
users["Alice"] = 30Нулевой слайс тоже равен nil, но с ним можно использовать append:
var nums []int
nums = append(nums, 10)Краткая шпаргалка
// Логический тип
bool
// Строка
string
// Целые числа со знаком
int
int8
int16
int32
int64
// Целые числа без знака
uint
uint8
uint16
uint32
uint64
uintptr
// Дробные числа
float32
float64
// Комплексные числа
complex64
complex128
// Псевдонимы
byte // uint8
rune // int32
any // interface{}
// Составные типы
[N]T // массив
[]T // слайс
map[K]V // мапа
struct // структура
// Другие типы
*T // указатель
func // функция
chan T // канал
interface // интерфейсИтог
Основные встроенные типы Go:
bool;- целочисленные типы;
- числа с плавающей точкой;
- комплексные числа;
string;- массивы;
- слайсы;
- мапы;
- структуры;
- указатели;
- функции;
- каналы;
- интерфейсы.
Кроме них, Go предоставляет псевдонимы byte, rune, any, а также встроенный интерфейс error.