Go (Golang) — многопоточный язык программирования, разработанный в 2009 году компанией Google. Он создан с целью упростить написание высокоэффективного ПО, а его синтаксис схож с языком Си.
В настоящей инструкции рассмотрим различные типы данных в 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
, а переменной salary
— int
.
В первую очередь, обратим внимание на основные типы данных.
Целочисленные типы данных в 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 также имеются специальные символы. Некоторые из них представлены ниже:
\n
— перевод строки. \t
— табуляция.\"
— двойная кавычка. \'
— одинарная кавычка. \\
— обратный слеш. Кроме того, существует возможность использовать 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)
Результат выполнения кода показан на картинке ниже.
Далее рассмотрим составные типы в Go.
Массивы в 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
.
Кроме того, функция make
имеет третий необязательный параметр, который обозначает вместимость (capacity). Он используется для предварительного указания объема памяти, который будет выделен для хранения элементов среза. Из-за уменьшения количества операций выделения памяти существенно снижается нагрузка на процессор.
Например:
slice := make([]int, 10, 20)
В данном фрагменте кода создается срез, содержащий 10 элементов с типом данных int
и с предварительно выделенной вместимостью на 20 элементов. Это значит, что срез изначально содержит 10 инициализированных нулевыми значениями элементов, и может расширяться до максимум 20 элементов без необходимости выделения дополнительной памяти. Если вдруг количество элементов среза станет больше 20, то Go автоматически выделит новый блок памяти, который будет в 2 раза больше предыдущего.
Подход с параметром capacity рекомендуется использовать, когда пользователю заранее известно максимальное количество элементов, которое потребуется хранить в срезе.
Чтобы получить доступ к элементам используется индексация, также как и с массивами.
Вкратце, структуры — это набор полей. Поля в свою очередь характеризуют различные атрибуты объектов.
Для объявления структуры в 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)
Вывод программы показан на картинке ниже.
Интерфейсы служат для определения набора методов, которые должен реализовать тип данных. Интерфейсы могут быть использованы для абстрагирования от конкретного типа данных и для реализации полиморфизма. Чтобы создать интерфейс в Go необходимо определить набор методов, которые должен реализовать тип данных.
Пример:
type Writer interface {
Write([]byte) (int, error)
}
Здесь определяется интерфейс Writer
, который должен иметь метод Write
с аргументом типа []byte
и возвращающий количество записанных байтов и ошибку.
В данной инструкции мы рассмотрели основные типы данных в Go. Кроме того, для каждого из них мы привели синтаксис объявления и рабочие примеры.
Надеемся, данная инструкция и советы в ней помогут вам научиться правильно выбирать типы данных в своем коде, что приведет к улучшению производительности разрабатываемых программ.
У make есть третий параметр для срезов (slices), так называемая глубина (capacity) которая обозначает ограничение сверху на количество элементов. Например,
slice := make([]int, 5,100)
создаст срез с 5ю элементами целого типа и максимум 100 элементами. Это тратит память (мы сразу запилили место под 100 элементов), но экономит проц, т.к. нам не нужно делать лишние вычисления. Это удобно, когда примерно понятно сколько будет элементов.
Очень полезное уточнение, спасибо. Дополнили статью 👌