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

Числа со знаком

// Диапазон: от -128 до 127.
// В памяти: 1 байт.
type int8 int8

// Диапазон: от -32_768 до 32_767.
// В памяти: 2 байт.
type int16 int16

// Диапазон: от -2_147_483_648 до 2_147_483_648.
// В памяти: 4 байт.
type int32 int32

// Диапазон: от -9_223_372_036_854_775_808 до 9_223_372_036_854_775_807.
// В памяти: 8 байт.
type int64 int64

9_223_372_036_854_775_808 — это девять квинтиллионов двести двадцать три квадриллиона триста семьдесят два триллиона тридцать шесть миллиардов восемьсот пятьдесят четыре миллиона семьсот семьдесят пять тысяч восемьсот семь.

Числа без знака


// Диапазон: от 0 до 255.
// В памяти: 1 байт.
type uint8 uint8

// Диапазон: от 0 до 65_535.
// В памяти: 2 байт.
type uint16 uint16

// Диапазон: от 0 до 4_294_967_295.
// В памяти: 4 байт.
type uint32 uint32


// Диапазон: от 0 до 18_446_744_073_709_551_615.
// В памяти: 8 байт.
type uint64 uint64

Для того, чтобы запомнить, сколько места в памяти занимает тот или иной тип данных, вы можете разделить число после типа на 8.

Например, для типа uint16: 16 / 8 = 2, тип uint16 занимает в памяти 2 байта

Платформозависимые типы данных


// int число со знаком, размер которого зависит от платформы.
// В памяти он занимает минимум 4 байта (32 бита) и не является алиасом для любых других целочисленных типов со знаком.
type int int

// uint имеет аналогичные характеристика как и int, но при этом не имеет знака
type uint uint

Почему int и uint занимают минимум 4 байта (32 бита) в Go?

Давайте представим, что разработчики языка Go сделали поддержку и теперь int на 16-и разрядных машинах будет иметь такой же диапазон как и int16 (от -32 _768 до 32_767), что это будет обозначать на практике?

Представим, что у нас есть следующий код:

var balance int = 40_000

Если мы запустим этот код на машине с разрядностью 32 или 64, то он отработает как ожидается.

Однако, при выполнении кода на 16-и битной машине мы получили бы переполнение, что приведет к изменению нашего баланса и мы получим -25536.

Переполнение в Go приводит к обрезке значения и не вызывает никакой паники.

При этом число 2 _147_483 _647 достаточен для решения большей части повседневных задач.

В очень старых версиях Go int был алиасом для типа int32

Интересный факт
https://stackoverflow.com/a/42351584
// uintptr целочисленный тип данных, размер которого достаточен, чтобы вместить любой указатель.
// Размер uintptr совпадает с размером слова процессора (word size).
type uintptr uintptr

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

Обратите внимание, что uintptr не является полноценным указателем, а представляет собой целочисленное значение без семантики указателя, в отличии от *T.

Различия и особенности указателей и uintptr мы рассмотрим в отдельном разделе.

На практике это обозначает, что GC (сборщик мусора) ничего не знает про указатели, которые хранятся в типах uintptr. Более того, uintptr не предотвратит утилизацию объекта и GC освободит объект на который указывал этот адрес. (1, 2).

Стоит отметить, что uintptr часто используется в низкоуровневом программировании, позволяя работать с: адресной арифметикой, системными вызовами.

Специальные типы данных

byte

// byte является алиасом для типа uint8, который ввели для того, чтобы было проще различать байтовые значения от 8-и битовых беззнаковых чисел
type byte = uint8

Так как тип byte не является самостоятельным типом, то все фукнции, которые работают с uint8 смогут работать и с byte значениями и наоборот.

Сам же тип byte был введен для того, чтобы различать семантику использования переменных, например:

// тип указывает, что элементы представляют низкоуровневые данные или ASCII/UTF-8 символы, а не маленькие числа
var byteData []byte

// тут наоборот, тип указывает, что мы работаем со срезом маленьких чисел
var uintData []uint8

С типом byte будет работать арифметика и при переполнении значения мы будем его обрезать.

Отметим, что []byte позволяет более эффективно работать со строками, которые в Go являются неизменяемыми типами данных.

s := "code"
b := []byte(s) // []byte{'c','o','d','e'}

В дополнение к типу byte в Go также существует тип rune.

rune

// rune является алиасом для типа int32, который ввели для того, чтобы было проще различать Unicode символы и целочисленные значения со знаком в коде.
type rune = int32

В UTF-8 один символ может включать больше одного байта. Например, символ `世` занимает 3 байта [E4, B8, 96].

Таким образом мы не можем полагаться на []byte(“世”), так как если мы отдельный байт, то испортим и символ и строку. Тип rune позволяет нам не задумываться об этом.

Работает это за счет стандартизации кодировки UTF-8. Например

Первый байтДлина символаПример
0xxxxxxx1 байтASCII символы
110xxxxx2 байта
1110xxxx3 байта
11110xxx4 байта
s := "Go世"
b := []byte(s) // [71 111 228 184 150]
// Преобразуем в двоичную систему
// [01000111, 01101111, 11100100, 10111000, 10010110]

// 71 (0x47) → ASCII 'G' → rune = 0x47 →  01000111
// 111 (0x6F) → ASCII 'o' → rune = 0x6F → 01101111

// 228 (0xE4) → 11100100 → первый байт 3-байтового символа, так как начинается с 1110
// следующие байты символа
// 184 (0xB8) → 10111000
// 150 (0x96) → 10010110 = 0x4E16 ('世')
// 

Подробнее устройство строк, кодировок и пакета utf8 в Go мы рассмотрим в отдельной статье.

iota

// iota является предварительно объявленным идентификатором, который можно использовать только в блоке const. Индексация значений начинается с нуля

const iota = 0

const (
    A = iota // 0
    B        // 1
    C        // 2
)

Тип данных iota также можно использовать с арифметическими выражениями:

const (
    A = iota + 5 // 5
    B            // 6
    C            // 7
)

А также битовыми выражениями, например:

const (
    KB = 1 << (10 * iota) // 1
    MB                    // 1_024
    GB                    // 1_048_576
)

Стоит отметить, что тип iota обнуляется в каждом блоке const

const (
    A1 = iota // 0
    B1        // 1
)
const (
    A2 = iota // 0, iota сбросился
    B2        // 1
)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *