Преобразование типов данных в Go

В Go типы данных используются для классификации данных по ряду характеристик, для определения значений, которые можно присвоить, и операций, которые можно выполнять над этими значениями. В программировании бывают случаи, когда нужно преобразовать значения одного типа в другой, чтобы по-другому с ними работать. Например, вам может потребоваться объединить числовые значения со строками или представить десятичные разряды в целочисленных значениях. Сгенерированным пользователем данным часто автоматически присваивается строковый тип, даже если эти данные состоят из чисел; для выполнения математических операций с этим вводом вам необходимо преобразовать строку в числовой тип данных.

Язык Go является статически типизированным, то есть типы данных в нем связаны с переменными, а не со значениями. Это означает, что если вы определяете переменную как int, она может быть только int. Позже вы не сможете присвоить ей строку, не преобразовав тип данных переменной. Статическая природа типов данных в Go – еще один важный повод подробно изучить способы их преобразования.

Читайте также: Основные типы данных в Go

В этом мануале вы на нескольких общих примерах научитесь преобразовывать числа и строки.

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

Go имеет несколько числовых типов данных. В основном числа делятся на два основных типа: целые числа и числа с плавающей точкой.

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

Преобразование целочисленных типов

Go поддерживает много целочисленных типов данных. Выбор одного или другого типа в основном зависит от его влияния на производительность; однако в некоторых случаях вам придется преобразовать один целочисленный тип в другой. Например, Go иногда автоматически генерирует числовые значения как int, а это может не соответствовать вашему входному значению. Если вы введете значение int64, вы не сможете использовать числа int и int64 в одном и том же математическом выражении, пока не преобразуете их типы данных соответствующим образом.

Предположим, у вас есть int8, и вам нужно преобразовать его в int32. Вы можете сделать это вот так:

var index int8 = 15
var bigIndex int32
bigIndex = int32(index)
fmt.Println(bigIndex)
15

Этот блок кода определяет index как тип данных int8 и bigIndex как тип данных int32. Чтобы сохранить значение index в bigIndex, он преобразует тип данных в int32. Для преобразования переменную index нужно заключить в int32().

Чтобы проверить тип данных, вы можете использовать оператор fmt.Printf и %T, для этого существует такой синтаксис:

fmt.Printf("index data type:    %T\n", index)
fmt.Printf("bigIndex data type: %T\n", bigIndex)
index data type:    int8
bigIndex data type: int32

Поскольку при этом используется оператор %T, оператор print выводит тип переменной, а не ее фактическое значение. Таким образом вы можете подтвердить, что тип данных был преобразован.

Вы также можете преобразовать большее целочисленное значение в меньшее целое число:

var big int64 = 64
var little int8
little = int8(big)
fmt.Println(little)
64

Имейте в виду, что при преобразовании целых чисел вы потенциально можете превысить максимальное значение типа данных:

var big int64 = 129
var little = int8(big)
fmt.Println(little)
-127

Сворачивание происходит, когда значение преобразуется в тип данных, который слишком мал для его хранения. В этом примере 8-битному типу данных int8 не хватило места для большого размера 64-битной переменной. При преобразовании большего типа данных в меньший тип всегда следует соблюдать осторожность, чтобы избежать случайного усечения данных.

Преобразование целых чисел в числа с плавающей точкой

Преобразование целых чисел в числа с плавающей точкой в Go похоже на преобразование одного целочисленного типа в другой. Вы можете использовать встроенные преобразования типов, заключая целое число в float64() или float32():

var x int64 = 57
var y float64 = float64(x)
fmt.Printf("%.2f\n", y)
57.00

Этот код объявляет переменную x типа int64 и инициализирует ее значение 57.

var x int64 = 57

float64() заключает в себя переменную x и преобразует значение 57 в значение с плавающей точкой 57.00.

var y float64 = float64(x)

Оператор %.2f  позволяет fmt.Printf форматировать число с двумя десятичными знаками.

Вы также можете использовать этот процесс в переменной. Следующий код объявляет переменную f со значением 57, а затем выводит новое значение с плавающей точкой:

var f float64 = 57
fmt.Printf("%.2f\n", f)
57.00

Используя float32() или float64(), вы можете конвертировать целые числа в числа с плавающей точкой. Далее вы узнаете, как преобразовать числа с плавающей точкой в ​​целые числа.

Преобразование чисел с плавающей точкой в целые числа

Go может преобразовывать числа с плавающей точкой в ​​целые числа, но при этом программа теряет точность числа с плавающей точкой.

Для этого можно заключить число с плавающей точкой в ​​int() (или же в один из архитектурно-независимых типов данных). Этот способ работает аналогично преобразованию одного целочисленного типа в другой. Вы можете добавить число с плавающей точкой в ​​скобках, чтобы преобразовать его в целое число:

var f float64 = 390.8
var i int = int(f)
fmt.Printf("f = %.2f\n", f)
fmt.Printf("i = %d\n", i)
f = 390.80
i = 390

Этот синтаксис преобразует число с плавающей точкой 390,8 в целое число 390, сбрасывая десятичное значение.

Вы также можете использовать этот метод с переменными. Следующий код объявляет переменную b как 125.0 и переменную c как 390.8, а затем выводит их как целые числа. Краткое объявление переменной (:=) сокращает синтаксис:

b := 125.0
c := 390.8
fmt.Println(int(b))
fmt.Println(int(c))
125
390

При преобразовании чисел с плавающей точкой в ​​целые числа с помощью int() Go обрезает десятичные значения, а оставшиеся числа с плавающей точкой образуют целое число. Обратите внимание, даже если вы захотите округлить 390,8 до 391, Go не сделает этого через тип int(). Вместо этого он опустит десятичную дробь.

Преобразование чисел через деление

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

a := 5 / 2
fmt.Println(a)
2

Если при делении любое из чисел является числом с плавающей точкой, то все типы будут автоматически объявлены как числа с плавающей точкой:

a := 5.0 / 2
fmt.Println(a)
2.5

Это делит число с плавающей точкой 5.0 на целое число 2, в результате чего получается  2.5 – число с плавающей точкой, которое сохраняет точность до десятых.

Преобразование строк

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

Преобразование чисел в строки

Вы можете преобразовать числа в строки, используя метод strconv.Itoa из пакета strconv в стандартной библиотеке Go. Если вы передадите число или переменную в скобки метода, это числовое значение будет преобразовано в строковое.

Давайте посмотрим на преобразование целых чисел. Чтобы преобразовать целое число 12 в строковое значение, вы можете передать 12 методу strconv.Itoa:

package main
import (
"fmt"
"strconv"
)
func main() {
a := strconv.Itoa(12)
fmt.Printf("%q\n", a)
}

При запуске этой программы вы получите следующий вывод:

"12"

Кавычки вокруг числа 12 означают, что число больше не является целым числом как таковым, теперь оно является строковым значением.

В коде используется оператор присваивания :=, чтобы объявить новую переменную a и присвоить ей значение, возвращаемое функцией strconv.Itoa(). В этом случае вы присвоили переменной значение 12. Также тут используется оператор %q в функции fmt.Printf, которая заключает предоставленную строку в кавычки.

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

package main
import (
"fmt"
)
func main() {
user := "8host"
lines := 50
fmt.Println("Congratulations, " + user + "! You just wrote " + lines + " lines of code.")
}

Когда вы запустите этот код, вы получите следующую ошибку:

invalid operation: ("Congratulations, " + user + "! You just wrote ") + lines (mismatched types string and int)

В Go объединять строки и целые числа нельзя, поэтому вам придется преобразовать переменную lines в строковые значения:

package main
import (
"fmt"
"strconv"
)
func main() {
user := "8host"
lines := 50
fmt.Println("Congratulations, " + user + "! You just wrote " + strconv.Itoa(lines) + " lines of code.")
}

Когда вы снова запустите код, вы получите следующий вывод, который поздравит пользователя с его прогрессом:

Congratulations, 8host! You just wrote 50 lines of code.

Если вы хотите преобразовать в ​​строку не целое число, а число с плавающей точкой, выполните аналогичные шаги и форматирование. Когда вы передаете число с плавающей точкой в метод fmt.Sprint, из пакета fmt в стандартной библиотеке Go будет возвращено строковое значение с плавающей точкой. Вы можете использовать либо само значение с плавающей точкой, либо переменную:

package main
import (
"fmt"
)
func main() {
fmt.Println(fmt.Sprint(421.034))
f := 5524.53
fmt.Println(fmt.Sprint(f))
}
421.034
5524.53

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

package main
import (
"fmt"
)
func main() {
f := 5524.53
fmt.Println("8host has " + fmt.Sprint(f) + " points.")
}
8host has 5524.53 points.

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

Преобразование строк в числа

Строки могут быть преобразованы в числа с помощью пакета strconv в стандартной библиотеке Go. В пакете strconv есть функции для преобразования как целых чисел, так и чисел с плавающей точкой. Это очень распространенная операция при приеме ввода от пользователя. Например, если у вас есть программа, запрашивающая возраст человека, при вводе ответа возраст записывается в виде строки. Затем вам нужно преобразовать его в int для выполнения математических операций.

Если в вашей строке нет десятичных разрядов, вы можете преобразовать ее в целое число с помощью функции strconv.Atoi. Если вы знаете, что будете использовать число как число с плавающей точкой, нужно использовать strconv.ParseFloat.

Давайте для примера посмотрим, как пользователь 8host отслеживает строки кода, написанные каждый день. Возможно, вы захотите выполнить какие-то математические операции с этими значениями, чтобы разнообразить вывод для пользователя. Но пока что эти значения хранятся в строках:

package main
import (
"fmt"
)
func main() {
lines_yesterday := "50"
lines_today := "108"
lines_more := lines_today - lines_yesterday
fmt.Println(lines_more)
}
invalid operation: lines_today - lines_yesterday (operator - not defined on string)

Поскольку два числовых значения были сохранены в строках, вы получили ошибку. Операнд вычитания – нельзя использовать для строковых значений.

Измените код, включив в него метод strconv.Atoi(), который преобразует строки в целые числа. Это позволит вам выполнять математические операции со значениями, которые изначально были строками. Поскольку при преобразовании строки в целое число существует вероятность сбоя, вы должны проверить наличие ошибок. Для этого вы можете использовать оператор if:

package main
import (
"fmt"
"log"
"strconv"
)
func main() {
lines_yesterday := "50"
lines_today := "108"
yesterday, err := strconv.Atoi(lines_yesterday)
if err != nil {
log.Fatal(err)
}
today, err := strconv.Atoi(lines_today)
if err != nil {
log.Fatal(err)
}
lines_more := today - yesterday
fmt.Println(lines_more)
}

Поскольку строка может не быть числом, метод strconv.Atoi() будет возвращать как преобразованный тип, так и потенциальную ошибку. При преобразовании lines_yesterday с помощью функции strconv.Atoi необходимо проверить возвращаемое значение err и убедиться, что оно было преобразовано. Если err  не равно nil, это означает, что метод strconv.Atoi не смог успешно преобразовать строковое значение в целое число. В этом примере мы использовали оператор if для проверки ошибки; если ошибка появлялась, log.Fatal регистрировал ее и выходил из программы.

Если вы запустите предыдущий код, вы получите:

58

Теперь попробуйте преобразовать строку, которая не является числом:

package main
import (
"fmt"
"strconv"
)
func main() {
a := "not a number"
b, err := strconv.Atoi(a)
fmt.Println(b)
fmt.Println(err)
}

Тут вы получите ошибку:

0
strconv.Atoi: parsing "not a number": invalid syntax

Поскольку переменная b была объявлена, но методу strconv.Atoi не удалось выполнить преобразование, переменной b не было присвоено значение. Обратите внимание, что b имеет значение 0. Это потому, что Go по умолчанию присваивает так называемые нулевые значения. Метод strconv.Atoi выдает ошибку и сообщает, почему не удалось преобразовать строку.

Преобразование строк и байтов

Строки в Go хранятся в виде фрагмента байтов. В Go вы можете преобразовать часть байт в строку, заключив ее в соответствующие методы []byte() и string():

package main
import (
"fmt"
)
func main() {
a := "my string"
b := []byte(a)
c := string(b)
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}

Здесь мы сохранили строковое значение в a, затем преобразовали его во фрагмент байтов b, а после этого преобразовали фрагмент байтов обратно в строку как c. Затем a, b и c будут выведены на экран:

my string
[109 121 32 115 116 114 105 110 103]
my string

Первая строка вывода – это исходная строка my string. Вторая строка – это фрагмент байт, который составляет исходную строку. Третья строка показывает, что байты можно преобразовать обратно в строку и отобразить на экране.

Заключение

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

Читайте также: Основные типы данных в Go

Tags: ,