Язык Go — кратко. Часть 1. Типы

Привет всем!

Сегодня я хочу поговорить о языке go (он же golang). О преимуществах и недостатках (с моей точки зрения, конечно) позже — я сам пока ещё только знакомлюсь с языком, хотя уже и пощупал кое-что.

Внешние пакеты

Начнём с того, как установить внешний пакет. На маке (думаю и в линуксе) всё легко и просто и работает с полпинка. На винде, к сожалению, я пока не разобрался, как заставить go «видеть» установленный git. И не уверен, что не вылезет других проблем. И всё же, вот пример команды:

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

Типы данных

Важные моменты о типах. Во-первых, операции можно производить только с одинаковыми типами. Это означает, что если у вас есть int32 и int8 переменные, то вы не можете их ни сложить, ни сравнить. Сначала надо явно преобразовать всё к одному типу.

С одной стороны, это то ещё извращение. С другой же, более чёткое понимание, что переменные одного типа и вы случайно не попытаетесь сложить число со строкой. Go строго типизированный язык. Это не так удобно, как в PHP или Python, зато и памяти ест куда меньше и работает шустрее.

Булево

bool с константами true и false

Целые

int8, int16, int32 = rune, int (32 или 64 бит в зависимости от платформы), int64
uint8 = byte, uint16, uint32, uint (32 или 64 бит в зависимости от платформы), uint64
uintptr — для хранения указателя

Вещественные и комплексные

float32, float64
complex64, complex128

Строки

Строки обычно задаются в двойных кавычках. Ещё можно задать строку в бэктиках (`) — это будет сырая строка (аналогично совмещению »’ и r» в питоне). Конкатенируются строки через +. Прочие операции со строками — через пакеты.

Имейте в виду, что len(«Моя строка») вернёт не количество символов (10), а размер в байтах (19). Символы в юникоде состоят из рун. Можно получить длину строки в рунах. Но она тоже не обязана быть верной.

Обратите внимание на последнюю строку. Она содержит один символ. Этот символ состоит из двух рун (обычный символ латиницы e и специальная руна-модификатор, похожая на обозначение ударения в русском языке). Эти две руны занимают три байта. С другой стороны, не всегда настолько важно считать именно символы. Обычно достаточно считать количество рун.

Байты

Задаются либо числом, либо символом в апострофах. 10 == ‘\n’

Переменные

Если переменная объявлена без явной инициализации, она автоматически инициализируется нулевым значением — 0, 0.0, false, «», nil.

Имена переменных — любые буквенно-числовые utf-8 (начиная с буквы). То есть, можно кириллические имена переменным давать. Или из греческого алфавита. Понятное дело, что имена стоит давать такие и с такими символами, которые смогут прочесть те, кто будет работать с кодом. Так что, хоть кириллицу и можно, но лучше латиницу использовать.

Константы

Синтаксис аналогичен синтаксису объявления переменных

Отличие нетипизированной числовой константы в том, что её можно использовать в любом выражении с любым числовым типом, а типизированную — только с таким же типом.

Перечисления

То есть, мы можем задать константы с явными значениями или «автоматически сгенерировать» значения за счёт iota. Йота — это эдакий встроенный автоинкрементатор. Обнуляется автоматически в новом блоке const. Если значения должны генерироваться одинаковыми образом, то достаточно указать для первого (iota во втором блоке и 1 << iota в третьем). Для следующих будет применяться то же выражение с автоинкрементацией iota на 1 (начинается с нуля). Никто не запрещает сделать так, что первые 4 константы будут битами (1 << iota), а для пятой и следующих просто числа. В этом случае для пятой надо указать значение iota. iota можно не только сдвигать, но использовать в любой арифметике (например, 10 * iota — добавление по 10 на каждом шаге).

Если надо пропустить какое-то значение iota, то вместо константы используем _. _ — это специальная «переменная/константа», которой не существует. Память для неё не выделяется, компилятор просто никуда не записывает присваиваемое значение. Эта же «переменная» полезна для игнорирования каких-то возвращаемых функцией значений (например, значения ошибки).

Массивы

Массивы вы вряд ли будете использовать часто. Дело в том, что они неизменяемые. И типы у нас «не совместимые», то есть туда, где ожидается массив на три инта, не выйдет подставить массив на 2 или 4 инта. Вместо этого вы будете использовать срезы, которые внутри содержат массивы. И всё же, вот синтаксис массивов.

Срезы

Срезы можно рассматривать как массивы с нежёсткими размерами, которые можно увеличивать за счёт append.

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

То есть, при переменная среза — это ссылка, а не непосредственно значения. И при присваивании одной переменной значения другого среза не происходит копирование данных, а лишь меняется ссылка. И потому когда внутренний массив заменяется, срез становится другим.

Правильное копирование срезов:

Копируется столько значений из slice5, на сколько хватает текущей ёмкости у slice6. Именно потому сначала сделали make с размером как у slice5.

А теперь вкратце, почему называется это срезами:

Получение среза из массива:

Внутренний массив будет оригинальным! То есть, изменение элемента в ary приведёт к изменению в slice9 и наоборот.

Приведение типов

При безопасном способе приведения в переменной ok будет true в случае успеха приведения, а в переменную x (или s) попадёт значение нужного типа. При небезопасном приведении в случае неудачи будет паника.

Leave a Reply

Ваш e-mail не будет опубликован. Обязательные поля помечены *