Tutorial

Конвертация типов данных в Go

GoDevelopment

Введение

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

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

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

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

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

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

Конвертация между целыми числами

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

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

var index int8 = 15

var bigIndex int32

bigIndex = int32(index)

fmt.Println(bigIndex)
Output
15

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

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

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

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

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

var big int64 = 64

var little int8

little = int8(big)

fmt.Println(little)
Output
64

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

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

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

Конвертация целых чисел в числа с плавающей точкой

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

var x int64 = 57

var y float64 = float64(x)

fmt.Printf("%.2f\n", y)
Output
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)
Output
57.00

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

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

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

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

var f float64 = 390.8
var i int = int(f)

fmt.Printf("f = %.2f\n", f)
fmt.Printf("i = %d\n", i)
Output
f = 390.80 i = 390

Этот синтаксис преобразовывает число с типом float 390.8 в целое число 390, отбрасывая все, что стоит после десятичного разделителя.

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

b := 125.0
c := 390.8

fmt.Println(int(b))
fmt.Println(int(c))
Output
125 390

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

Числа, конвертируемые с помощью деления

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

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

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

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

Здесь число типа float 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)
}

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

Output
"12"

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

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

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

package main

import (
    "fmt"
)

func main() {
    user := "Sammy"
    lines := 50

    fmt.Println("Congratulations, " + user + "! You just wrote " + lines + " lines of code.")
}

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

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

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

package main

import (
    "fmt"
    "strconv"
)

func main() {
    user := "Sammy"
    lines := 50

    fmt.Println("Congratulations, " + user + "! You just wrote " + strconv.Itoa(lines) + " lines of code.")
}

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

Output
Congratulations, Sammy! You just wrote 50 lines of code.

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

package main

import (
    "fmt"
)

func main() {
    fmt.Println(fmt.Sprint(421.034))

    f := 5524.53
    fmt.Println(fmt.Sprint(f))
}
Output
421.034 5524.53

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

package main

import (
    "fmt"
)

func main() {
    f := 5524.53
    fmt.Println("Sammy has " + fmt.Sprint(f) + " points.")
}
Output
Sammy has 5524.53 points.

Вы можете быть уверены, что преобразование типа float в string было выполнено успешно, поскольку конкатенация выполняется без ошибок.

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

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

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

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

package main

import (
    "fmt"
)

func main() {
    lines_yesterday := "50"
    lines_today := "108"

    lines_more := lines_today - lines_yesterday

    fmt.Println(lines_more)
}
Output
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 для сохранения ошибки и выхода из программы.

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

Output
58

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

package main

import (
    "fmt"
    "strconv"
)

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

Вы получите следующую ошибку:

Output
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. Затем вы выводите а, b и с на экран:

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

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

Заключение

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

Если вы хотите более подробно познакомиться с типами данных в Go, ознакомьтесь с нашей статьей Знакомство с типами данных в Go.

Creative Commons License