Конвертирование данных в Golang

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

Содержание статьи

Представьте, что вы пришли в магазин, где нужно сделать покупки по списку жены. Первым пунктом значится молоко, но больше ничего не уточняется — коровье, козье, соевое? Оно должно быть органическим, обезжиренным, 1%, 2%, цельным, конденсированным? Сколько пакетов? Станете ли вы звонить жене для уточнения?

Форум Гоферов

Мы работаем над форумом для программистов на Golang. Очень нужны модераторы которые хотят помочь с ответами для новичков и помочь в развитии Go-сообщества.

Go на Форум

Уроки, статьи и Видео

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

Go в ВК Go в Telegram

Жене наверняка будет действовать на нервы, если вы будете звонить ей из-за каждой мелочи. Какая капуста? Картофель белый или красный? Один или два килограмма? С другой стороны, если вы возьмете продукты на свое усмотрение и вернетесь домой с шоколадным молоком и чипсами, все закончится не очень хорошо.

Если представить, что в данной ситуации ваша жена программист, а вы компилятор, какой подход будет оптимальным со стороны Golang?

Можно ли смешивать типы в Golang?

Поведение переменной зависит от ее типа. Числа могут складываться, а строки объединяться. Для объединения двух строк нужно использовать оператор плюс:

При попытке объединить число и строку компилятор Go выведет ошибку:

В некоторых других языках программирования при попытке оперировать переменными разных типов производится попытка угадать намерения разработчика. К примеру, JavaScript и PHP могут вычесть 1 из строки «10»:

Компилятор Go не примет "10" - 1 и выдаст ошибку несовпадения типов. В Go вначале нужно конвертировать строку "10" в тип integer. Функция Atoi из пакета strconv выполнит конвертацию, однако если строка не содержит реального числа, появится ошибка. К моменту, когда ошибка будет исправлена, версия Go достигнет длины в четыре строки, что не очень удобно.

Учитывая все вышесказанное, если "10" является вводом пользователя или данными, полученными из внешнего источника, JavaScript и PHP также должны сделать проверку на реальность числа.

В языках, где тип принуждается, поведение кода менее предсказуемо, особенно для тех, кто не знаком с мириадами неясных поведений. Оператор плюс (+) в Java и JavaScript переводит числа в строки, конкатенируя их, в то время как PHP складывает числовые значения:

При попытке сделать нечто подобное в Go выведется ошибка.

Другим примером несовпадения типов является попытка сделать вычисления между целыми и вещественными числами. Числа с плавающей запятой вроде 365.2425 представлены вещественными типами float, а целые числа Go сопоставляет с типами integer:

Если бы все три переменные были целыми числами, вычисления были бы успешными, однако тогда значение переменной earthDays равнялось бы 365, а не 365.2425. Альтернативно, вычисления стали бы успешными, если бы переменные age и marsDays принадлежали к вещественному типу (41.0 и 687.0). Go не делает предположения касательно того, что вам нужно, но вы сами можете конвертировать типы. Это будет рассмотрено далее.

Вопрос для проверки:

Что будет результатом операции "10" - 1 в Go?

Конвертация числовых типов данных в Golang

Конвертация типов в Go является очень прямым. Если для вычисления нужно, чтобы тип целочисленной переменной age стал вещественным, требуется указать это следующим образом:

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

Также можно конвертировать float в integer. Однако десятичная часть после точки при этом уберется, без округления:

Конвертация типов требуется для неподписанных (unsigned) и подписанных (signed) целочисленных типов, а также для типов с разными размерами. Всегда лучше конвертировать в тип с большим диапазоном, к примеру, из int8 в int32. Другие целочисленные конвертации не обходятся без рисков. uint32 может содержать значение в 4 миллиарда, однако int32 поддерживает числа не более 2 миллиардов. Также int может содержать отрицательное число, а uint нет.

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

Вопросы для проверки: 

  1. Как можно конвертировать переменную red в неподписанный 8-битный целочисленный тип?
  2. Каким будет результат сравнения age > marsAge?

На что обратить внимание при конвертации типов Go

В 1996 году беспилотная ракета Arianne 5 сошла с траектории полета и взорвалась через 40 секунд после запуска. Причиной была ошибка конвертации типа из float64 в int16 со значением, превышающим 32 767 — максимальное значение, которое может содержать int16. Необработанная ошибка оставила систему управления полетом без данных для траектории, из-за чего ракета отклонилась от курса, сломалась и в конечном итоге взорвалась.

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

Если значение bh равно 32 767, что слишком велико для int16, результатом будет ожидаемый итог работы с целыми числами Go: тип переполняется, переходя к минимальному возможному значению для int16 а именно -32768.

Язык Ada, использовавшийся для Arianne 5, действует иначе. Конвертация типа из float64 в int16 со значением, превышающим допустимый диапазон, привела к ошибке в программном обеспечении. Согласно отчету, рассматриваемое вычисление имело смысл только до момента взлета, поэтому в данной ситуации подход Go может быть лучше. Однако в большинстве случаев лучше избегать неточностей в данных.

Для определения того, приведет ли конвертация типа в int16 к недопустимому значению, пакет math предоставляет константы min/max:

На заметку: Константы min/max являются нетипизированными, что допускает сравнение bh, вещественного значения, с MaxInt16. Подробнее о нетипизированных константах можете прочитать в статье Пакет Big — Крупные числа в Golang и примеры их использования.

Задание для проверки:

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

Конвертация строк в Golang

Для конвертации типов rune или byte в string можно использовать такой же синтаксис, что нужен для конвертации числовых типов. Это показано в следующем листинге. Результат аналогичен с тем, что получается при использования специального символа %c , описанного в предыдущей статье про обработку строк, для отображения рун и байтов в виде символов.

Конвертация цифрового кода в строку работает также, как и в случае с типом integer. В конечном итоге, rune и byte являются просто другими названиями для int32 и uint8.

Для конвертирования чисел в string, каждое число нужно сначала конвертировать в код, начинающийся с 48 для символа 0, и заканчивающийся на 57 для символа 9. К счастью, функция Itoa пакета strconv (string conversion, то есть конвертация строк) делает это за нас, как показано в следующем листинге:

На заметку: Слово Itoa является аббревиатурой — integer to ASCII, то есть от целого числа к ASCII. Юникод является расширенным набором старого стандарта ASCII. Первые 128 кодов такие же — числа, используемые здесь, английские буквы и стандартные знаки препинания.

Другим способом конвертации числа в строку является использование Sprintf, своеобразной напарницы Printf, что возвращает строку string, но не отображает ее:

Есть еще один способ. В пакете strconv есть функция Atoi (ASCII to integer, то есть от ASCII к целому числу). Из-за того, что в строке могут быть какие-то кракозябры или слишком крупные числа, функция Atoi может вернуть ошибку:

Значение nil для err указывает, что ошибки нет, и все хорошо. В одном из следующих уроков это будет рассмотрено подробнее.

Вопрос для проверки:

Назовите две функции, что конвертируют целое число в строку.

Статические типы данных Golang

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

В языках вроде JavaScript, Python и Ruby вместо статической используется динамическая типизация. В данных языках у каждого значения есть ассоциируемый тип, и переменные могут содержать значения любого типа. Данные языки позволили бы countdown изменить свой тип во время выполнения программы.

В Golang есть запасной выход на случай ситуаций, где тип непонятен. К пример, функция Println принимает как строки, так и числовые типы float или integer. В следующих уроках функция Println будет рассмотрена в деталях.

Конвертация булевых значений Golang

Группа функций Print отображает булевы значения true и false в виде текста. В следующем примере используется функция Sprintf для конвертации булевой переменной launch в текст. Если сделать конвертацию булева типа в численный или текстовых, простой оператор if подойдет лучше всего.

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

При попытке конвертировать булево значение через конструкции вроде string(false), int(false), bool(1) или bool("yes") компилятор Go выведет сообщение об ошибке.

На заметку: В языках программирования без выделенного типа bool значения 1 и 0 зачастую соответствуют значениям true и false соответственно. Однако в Go у булева типа нет численных эквивалентов.

Вопрос для проверки:

Как можно конвертировать булев тип в целое число, чтобы 1 соответствовала значению true, а 0 — false?

Заключение

  1. Конвертация между типами точна, что позволяет избежать двусмысленности;
  2. Пакет strconv предоставляет функции для конвертации строк в другие типы и наоборот.

Итоговое задание для проверки:

Напишите программу, что конвертирует строки в булевы значения:

  • Строки «true», «yes» или «1» соответствуют значению true;
  • Строки «false», «no» или «0» соответствуют значению false;
  • Для других значений выводит сообщение об ошибке.

Обратите внимание, что здесь можно использовать оператор switch, что принимает по несколько значений на случай case.

Понравилась статья?

Поддержи наш проект, чтобы мы могли создать больше хорошего контента!