Типы данных в Go

Илья Ушаков
Илья Ушаков
Технический писатель
03 мая 2023 г.
703
9 минут чтения
Средний рейтинг статьи: 5

Go (Golang) — многопоточный язык программирования, разработанный в 2009 году компанией Google. Он создан с целью упростить написание высокоэффективного ПО, а его синтаксис схож с языком Си.

Image12

В настоящей инструкции рассмотрим различные типы данных в Go, а также предложим рекомендации по их выбору.

Объявление переменных

Объявление переменной — это процесс ее создания и назначения ей имени и типа данных. В Go переменные могут быть объявлены с помощью ключевого слова var, а также с помощью оператора :=.

Синтаксис объявления переменных с использованием var:

var variable_name data_type

А вот так выглядит объявление переменных через var:

var FirstName string
var salary float32

Теперь рассмотрим второй способ объявления переменных, а именно с инициализацией, т.е. с указанием начального значения при их создании. 

Синтаксис объявления переменных с инициализацией выглядит следующим образом:

var variable_name data_type = value

А вот так выглядит объявление на примерах:

var FirstName string = "Ilya"
var salary float32 = 35000

Кроме всего перечисленного, существует краткий способ объявления переменных с помощью оператора :=. Данный способ автоматически задает тип переменной при указании значения. Синтаксис:

variable_name := initial_value

Примеры:

FirstName  := "Ilya"
salary := 35000

Как видно по картинке ниже, переменной FirstName автоматически присваивается тип string, а переменной salaryint.

Image9

Основные типы данных

В первую очередь, обратим внимание на основные типы данных.

Image10

Целочисленные типы данных

Целочисленные типы данных в Go описывают целочисленные значения, которые могут быть положительными, отрицательными или нулевыми. В Go существует несколько типов целочисленных данных, которые отличаются друг от друга размером в байтах. Рассмотрим каждый из них подробнее в таблице ниже.

Тип

Описание

Диапазон чисел

int8

8-битные числа со знаком. 

от -128 до 127

int16

16-битные числа со знаком. 

от -32,768 до 32,767

int32

32-битные числа со знаком. 

от -231 до 231-1

int64

64-битные числа со знаком. 

от -263 до 263-1

int

Представляет собой 32-битные или 64-битные числа со знаком (в зависимости от платформы). Он используется для работы с целочисленными значениями по умолчанию.

Как у int32 или int64 (в зависимости от платформы)

uint8

8-битные числа без знака.

от 0 до 255

uint16

16-битные числа без знака.

от 0 до 65,535

uint32

32-битные числа без знака.

от 0 до 232-1

uint64

64-битные числа без знака.

от 0 до 264-1

uint

Представляет собой 32-битные или 64-битные числа без знака (в зависимости от платформы).

Как у uint32 или uint64 (в зависимости от платформы)

Кроме перечисленных, еще есть byte и rune. Они эквиваленты uint8 и int32 соответственно.

Примеры объявления целочисленных переменных:

var x int16 = 45000
var y uint = 73000
var z byte = 4

Вещественные типы данных

Вещественные типы данных используются для хранения дробных чисел. В Go предложено 2 варианта: float32 и float64.

  • float32 занимает 4 байта в памяти и может хранить числа с плавающей точкой от -3.4028235E+38 до 3.4028235E+38 с точностью до 7 знаков после запятой; 
  • float64 занимает 8 байт в памяти и может хранить числа с плавающей точкой от -1.7976931348623157E+308 до 1.7976931348623157E+308 с точностью до 15 знаков после запятой.

Важно понимать, что вещественные числа в компьютере представлены в двоичной форме, и поэтому могут быть неточными. Это может приводить к ошибкам округления при выполнении операций с такими числами. Поэтому при работе с ними важно учитывать особенности их представления в компьютере и принимать меры для избежания ошибок округления.

Примеры объявления вещественных переменных:

var x float32 = 3.14
var y float64 = 3.1415926535897

Строковые типы данных

Строковые типы данных в Go используются для хранения символьных строк. Каждый символ строки представляет собой последовательность байтов в памяти.

Строки являются неизменяемыми (immutable) объектами в Go. Это означает, что после создания строки ее содержимое не может быть изменено. Однако, можно создать новую строку, объединив несколько существующих строк.

В Go также имеются специальные символы. Некоторые из них представлены ниже:

  1. \n — перевод строки. 
  2. \t — табуляция.
  3. \" — двойная кавычка. 
  4. \' — одинарная кавычка. 
  5. \\ — обратный слеш. 

Кроме того, существует возможность использовать Unicode-символы. Для этого можно использовать последовательность символов в формате \uXXXX, где XXXX — это шестнадцатеричное значение Unicode-кода символа.

Примеры объявления строковой переменной:

var exampleText1 string = "Hello, user1!"
exampleText2 := "Hello, user2!"

Логический тип данных

В Go есть логический тип данных bool, который может принимать значения true и false.

Данный тип данных может использоваться для хранения значений логических выражений, например, в условных операторах if и switch, а также в логических операциях, таких как && (логическое И), || (логическое ИЛИ) и ! (логическое НЕ).

Например, мы можем использовать логический тип данных в следующем коде:

age := 18
isAdult := age >= 18
fmt.Println(isAdult)

Результат выполнения кода показан на картинке ниже.

Image7

Составные типы данных

Далее рассмотрим составные типы в Go.

Image11

Массивы

Массивы в Go применяются для хранения фиксированного количества элементов одного типа. Главное отличие от других языков в том, что здесь массивы являются значениями, а не ссылками на данные. 

Для определения массива необходимо указать тип элемента и количество элементов в квадратных скобках. Например:

var exampleArr [4]int = [4]int{2, 5, 7, 9}

Доступ к элементам массива осуществляется по индексу, начиная с 0:

fmt.Println(exampleArr[0])

Массивы в Go также поддерживают итерацию с помощью цикла for:

for i := 0; i < len(exampleArr); i++ {
    fmt.Println(exampleArr[i])
}

Подробнее о циклах for в языке Go мы писали в этой статье.

Срезы

Срезы (Slices) в Go — это ссылочный тип данных, который представляет собой динамический массив элементов, хранящихся в памяти. Они очень похожи на массивы, но в отличие от них, их размер может корректироваться во время выполнения программы, а также они являются ссылками на данные, а не значениями.

Определение среза осуществляется с помощью следующей синтаксической конструкции:

var slice []T

Где T — тип элементов среза, а slice — переменная, хранящая ссылку на срез.

Пустой срез может быть объявлен так:

emptySlice := []int{}

Для инициализации среза можно использовать функцию make, которая создает новый срез заданной длины:

slice := make([]int, 5)

В примере выше создается срез пяти элементов типа int.

Чтобы получить доступ к элементам используется индексация, также как и с массивами.

Структуры

Вкратце, структуры — это набор полей. Поля в свою очередь характеризуют различные атрибуты объектов. 

Для объявления структуры в Go используется ключевое слово type, далее указывается имя структуры и ее определение в фигурных скобках. Например, ниже в примере объявим структуру, представляющую информацию о человеке:

type Person struct {
    Name    string
    Age     int
    Address string
}

Для создания переменной, хранящей значения структуры, нужно использовать ключевое слово var и имя переменной. Затем после имени переменной следует имя структуры, за которым следует фигурные скобки со значениями полей структуры в виде имя_поля: значение. Например:

var person1 Person
person1 = Person{Name: "John", Age: 30, Address: "123 Main St."}

Здесь мы объявляем переменную person1 типа Person и присваиваем ей значения для каждого поля. Можно также использовать короткую форму инициализации структуры:

person2 := Person{Name: "Jane", Age: 25, Address: "456 Elm St."}

Доступ к полям структуры осуществляется с помощью оператора точки (.). Например, чтобы получить имя person1, нужно написать:

person1.Name

Структуры могут содержать внутри себя другие структуры и даже ссылки на самих себя (так называемые рекурсивные структуры). Кроме того, они могут реализовывать интерфейсы.

Карты

Карта (map) является ссылочным типом данных, который используется для представления неупорядоченного набора пар ключ-значение. Ключи в карте должны быть уникальными, но значения могут повторяться.

Чтобы создать карту, используется встроенная функция make(), которой передаются типы ключа и значения. Следующий код создает пустую карту с ключами string и значениями int:

m := make(map[string]int)

Чтобы добавить элемент в карту, можно использовать следующую форму записи:

m[key] = value

Где key — ключ элемента, а value — значение элемента. Например:

m["apple"] = 3
m["banana"] = 5

Чтобы получить значение элемента по ключу, используется следующая форма записи:

value := m[key]

Например, для получения значения элемента с ключом apple:

count := m["apple"]

Если элемента с указанным ключом нет в карте, то будет возвращено значение по умолчанию. 

Чтобы удалить элемент из карты, можно использовать встроенную функцию delete(). Следующий код удаляет элемент с ключом apple:

delete(m, "apple")

В Go карты реализованы в виде хеш-таблиц, поэтому порядок элементов в карте не фиксирован и может меняться при каждом выполнении программы. Также следует обратить внимание на то, что карта не является потокобезопасной, поэтому при параллельном доступе к карте необходимо воспользоваться механизмами синхронизации доступа (мьютексы или каналы).

Указатели и интерфейсы

Указатели 

Указатели необходимы для взаимодействия с переменными, хранящими адреса в памяти. Они могут быть определены с помощью символа & перед переменной, а для получения значения, на которое указывает указатель, используется символ *

Пример:

var myInt int = 42
var myIntPointer *int = &myInt
fmt.Println(*myIntPointer) 

Вывод программы показан на картинке ниже.

Image8

Интерфейсы

Интерфейсы служат для определения набора методов, которые должен реализовать тип данных. Интерфейсы могут быть использованы для абстрагирования от конкретного типа данных и для реализации полиморфизма. Чтобы создать интерфейс в Go необходимо определить набор методов, которые должен реализовать тип данных. 

Пример:

type Writer interface {
    Write([]byte) (int, error)
}

Здесь определяется интерфейс Writer, который должен иметь метод Write с аргументом типа []byte и возвращающий количество записанных байтов и ошибку.

Заключение

В данной инструкции мы рассмотрели основные типы данных в Go. Кроме того, для каждого из них мы привели синтаксис объявления и рабочие примеры. 

Надеемся, данная инструкция и советы в ней помогут вам научиться правильно выбирать типы данных в своем коде, что приведет к улучшению производительности разрабатываемых программ.

Зарегистрируйтесь и начните пользоваться
сервисами Timeweb Cloud прямо сейчас

15 лет опыта
Сосредоточьтесь на своей работе: об остальном позаботимся мы
165 000 клиентов
Нам доверяют частные лица и компании, от небольших фирм до корпораций
Поддержка 24/7
100+ специалистов поддержки, готовых помочь в чате, тикете и по телефону