Шаг 14.
Язык программирования Go.
Целые числа в Go

    На этом шаге рассмотрим целочисленные типы данных в Go.

    Язык обеспечивает как знаковую, так и беззнаковую целочисленную арифметику. Имеются знаковые целые числа четырех размеров - 8, 16, 32 и 64 бита, - представленные типами int8, int16, int32 и int64, а также соответствующие беззнаковые версии uint8, uint16, uint32 и uint64. Для большинства ситуаций достаточно использовать единственный целочисленный тип int. Переменные этого типа подходят для использования в качестве счетчиков циклов, индексов массивов и срезов и арифметических вычислений общего назначения.

    Тип rune является синонимом для типа int32 и по соглашению указывает, что данное значение является символом Unicode. Эти два имени могут использоваться взаимозаменяемо. Тип byte является синонимом для типа uint8 и подчеркивает, что это значение является фрагментом неформатированных данных, а не малым числом.

    Имена и диапазоны значений представлены в таблице 1.

Таблица 1. Целочисленные типы и диапазоны представляемых значений
Тип Диапазон представляемых значений
byte Синоним типа uint8
int Диапазон int32 или int64, в зависимости от реализации
int8 [-128, 127]
int16 [-32768, 32767]
int32 [-2147483648, 2147483647]
int64 [-9223372036854775808, 9223372036854775807]
rune Синоним типа int32
uint Диапазон uint32 или uint64, в зависимости от реализации
uint8 [0, 255]
uint16 [0, 65535]
uint32 [0, 4294967295]
uint64 [0, 18446744073709551615]
uintptr Беззнаковое целое, пригодное для хранения значения указателя

    В таблице 2 представлены арифметические операторы, применяющиеся только к встроенным целочисленным типам.

Таблица 2. Арифметические операторы, применимые только к встроенным целочисленным типам
Оператор Описание/результат
^x Поразрядное дополнение значения x
x %= y Присваивает переменной x остаток от деления x на y; деление на нуль вызывает аварию
x &= y Присваивает переменной x результат поразрядной операции "И" над значениями x и y
x |= y Присваивает переменной x результат поразрядной операции "ИЛИ" над значениями x и y
x ^= y Присваивает переменной x результат поразрядной операции "исключающее ИЛИ" над значениями x и y
x &^= y Присваивает переменной x результат поразрядной операции "И-НЕ" над значениями x и y
x >>= u Присваивает переменной x результат поразрядного сдвига вправо значения x на беззнаковое целое число u бит
x <<= u Присваивает переменной x результат поразрядного сдвига влево значения x на беззнаковое целое число u бит
x % y Остаток от деления x на y; деление на нуль вызывает аварию
x & y Операция "поразрядное И"
x | y Операция "поразрядное ИЛИ"
x ^ y Операция "поразрядное исключающее ИЛИ"
x &^ y Операция "поразрядное И-НЕ"
x << u Поразрядный сдвиг влево значения x на беззнаковое целое число u бит
x >> u Поразрядный сдвиг вправо значения x на беззнаковое целое число u бит

    Если результат арифметической операции, как знаковой, так и беззнаковой, имеет больше битов, чем может быть представлено типом результата, мы говорим о переполнении (overflow). При этом старшие биты, которые не помещаются в результате, отбрасываются. Если исходное число имеет знаковый тип, результат может быть отрицательным, если левый бит равен 1, как показано в следующем примере с int8:

var u uint8 = 255
fmt.Println(u, u+1, u*u) // "255 0 1"
var i int8 = 127
fmt.Println(i, i+1, i*i)  // "127 -128 1"

    Архив примера можно взять здесь.

    Рассмотрим пример использования битовых операций для интерпретации значения uint8 в качестве набора восьми независимых битов. Он использует символы преобразования %b в Printf для вывода двоичных цифр числа; 08 уточняет поведение %b, заставляя дополнять результат нулями так, чтобы выводилось ровно 8 цифр.

var x uint8 = 1<<1 | 1<<5
var y uint8 = 1<<1 | 1<<2
fmt.Printf("%08b\n", x) // "00100010", множество {1,5}
fmt.Printf("%08b\n", y) // "00000110", множество {1,2}
fmt.Printf("%08b\n", x&y) // "00000010", пересечение {1}
fmt.Printf("%08b\n", x|y) // "00100110", объединение {1,2,5}
fmt.Printf("%08b\n";, x^y) // "00100100", симметричная разность {2,5}
fmt.Printf("%08b\n", x&^y) // "00100000", разность {5}
for i := uint(0); i < 8; i++ {
    if x&(1<<i) != 0 { // Проверка принадлежности множеству
       fmt.Println(i) // "1", "5"
    }
}
fmt.Printf("%08b\n", x<<1) // "01000100", множество {2,6}
fmt.Printf("%08b\n", x>>1) // "00010001", множество {0,4}

    Архив примера можно взять здесь.

    Целочисленные литералы любого размера и типа могут быть записаны как десятичные числа, как восьмеричные числа, если они начинаются с 0 (как 0666), или как шестнадцатеричные, если они начинаются с или (как 0xabc). Шестнадцатеричные цифры могут быть как прописными, так и строчными. При выводе чисел с использованием пакета fmt можно управлять системой счисления и форматом вывода с помощью символов преобразования %d, %o и , как показано в следующем примере:

о := 0666
fmt.Printf("%d %[1]о %#[1]о\n", о) // "438 666 0666"
x := int64(0xabc)
fmt.Printf("%d %[1]x %#[1]x %#[1]X\n", x) // "2748 abc 0xabc 0XABC"

    Архив примера можно взять здесь.

    Форматная строка Printf содержит несколько символов преобразования %, которые требуют того же количества дополнительных аргументов, но [1] после % говорит функции Printf о том, что ей следует использовать первый операнд снова и снова. Во-вторых, наличие # при символах преобразования , или говорит функции Printf о том, что при выводе должен быть добавлен префикс, указывающий систему счисления - 0, или соответственно.

    Литералы записываются как символ в одинарных кавычках. Простейший пример с использованием ASCII-символа - 'а', но так можно записать любой символ Unicode - либо непосредственно, либо с помощью числовых управляющих последовательностей (начинаются с символа \).

    Руны выводятся с помощью символов преобразования , или %q - если требуются апострофы. Например:

ascii := 'а'
Unicode := '★'
newline := '\n'
fmt.Printf("%d %[1]c %[1]q\n", ascii) // "97 a 'a'"
fmt .Printf ("%d %[1]c %[1]q\n", Unicode) // "9733 ★ '★'"
fmt.Printf("%d %[1]q\n", newline) // "10 '\n'"

    Архив примера можно взять здесь.

    На следующем шаге рассмотрим вещественные типы данных в Go.


Предыдущий шаг Содержание Следующий шаг