Go — статически типизированный язык программирования. Типы данных в нем привязаны к переменным. Если вы задали, что переменная имеет тип int и предназначена для хранения некоторых чисел, то не сможете сохранить в нее строку (string). Это правило действует и в обратном направлении.
Статическая типизация предохраняет разработчиков от ошибок, когда программа ожидает один data type, а получает другой. Но также жесткая привязка является ограничением для выполнения некоторых операций. Для преодоления этого ограничения в Go есть конвертация типов данных, или преобразование типов данных. Это формализованная процедура, которая позволяет разработчикам превращать целочисленные значения в числа с плавающей точкой, строки — в числа и наоборот. Статья поможет вам разобраться, как это делать.
Но сначала давайте посмотрим, какие есть типы данных в Go.
cloud
Основные типы в Golang:
bool // Boolean, имеет значение True или False
string // Строки
int int8 int16 int32 int64 // Целочисленные значения со знаком
uint uint8 uint16 uint32 uint64 uintptr // Целочисленные значения без знаков
byte // alias для uint8
rune // alias для int32
float32 float64 // Числа с плавающей точкой
complex64 complex128 // Комплексные числа
Int, uint, и uintptr имеют ширину 32 бита в 32-битных системах и 64 бита в 64-битных системах. Когда вам нужно целочисленное значение, вы должны использовать int, если только у вас нет особой причины использовать размерный или беззнаковый целочисленный тип.
Golang не имеет типа данных char. Язык использует byte и rune для представления значений символов. Byte представляет символы ASCII, а rune — более широкий набор символов Unicode, закодированных в формате UTF-8.
Чтобы определить символы в Golang, заключите их в одинарные кавычки следующим образом: 'a'. Типом по умолчанию для символьных значений является rune. Если вы не объявляете тип явно при объявлении переменной с символьным значением, то Go выведет тип как rune:
var firstLetter = 'A' // Type inferred as `rune` (Default type for character values)
Вы можете создать переменную byte, явно указав тип:
var lastLetter byte = 'Z'
Byte и rune являются целыми числами. Например, byte со значением 'a' преобразуется в целое число 97. Точно так же rune со значением Юникода '♥' преобразуется в соответствующую кодовую точку Юникода U+2665, где U+ означает Юникод, а числа являются шестнадцатеричными, что по существу является целым числом.
package main
import "fmt"
func main() {
var myByte byte = 'a'
var myRune rune = '♥'
fmt.Printf("%c = %d and %c = %U\n", myByte, myByte, myRune, myRune)
}
Вывод:
a = 97 and ♥ = U+2665
Когда перед вами стоит задача выполнить в golang convert int to string или наоборот, string to int, это значит, что необходимо взять тот type, который изначально был задан переменной, и превратить его в другой type. Как было сказано выше, эти действия в языке строго формализованы. Примеры из статьи помогут вам разобраться с основами таких преобразований.
Конвертация числовых типов может пригодиться при решении разных задач. Например, к вам приходит продакт-менеджер и говорит, что нужно срочно добавить на сайт калькулятор, который выполняет только одно действие — деление. Главное, чтобы результат был точным до последнего символа.
Однако при делении двух переменных с integer результат может оказаться неточным. Смотрите:
package main
package main
import "fmt"
func main() {
var first int = 15
var second int = 6
var result = first / second
fmt.Println(result)
}
После выполнения этого кода вы получите 2. Программа вывела ближайшее целочисленное частное. Но это очень далеко от точного деления. Такой калькулятор точно никому не нужен.
Чтобы повысить точность, необходимо привести обе переменные к float.
package main
import "fmt"
func main() {
var first int = 15
var second int = 6
var result = float64(first) / float64(second)
fmt.Println(result)
}
В этом случае вывод будет точным — 2.5. Добиться этого оказалось очень просто. Достаточно обернуть переменную конструкцией float64() или float32(). Теперь калькулятор можно запускать. Продуктовые метрики нас не интересуют. Главное, что с технической стороны фича реализована четко.
При делении можно обойтись и без явного приведения к float. Если вы используете числа с плавающей точкой, то все остальные типы автоматически приводятся к float. Выполните этот код:
package main
import "fmt"
func main() {
a := 5.0 / 2
fmt.Println(a)
}
В выводе будет 2.5, несмотря на то, что вы не использовали в коде обертку float64() или float32(). Компилятор Go видит, что float 5.0 делится на целое число 2 и сохраняет точность деления, выводя результат в виде числа с плавающей точкой.
В первом примере с делением вы явно приводили целые числа к типу float с помощью конструкции float64(). Еще один пример:
package main
import "fmt"
func main() {
var x int64 = 57
var y float64 = float64(x)
fmt.Printf("%.2f\n", y)
}
После выполнения этой функции на экране отобразится 57.00. Два нуля после точки появились, потому что вы добавили конструкцию "%.2f\n". Вместо двойки можно указать десять или любое другое значение — зависит от того, сколько знаков после точки вам нужно.
В обратную сторону приведение тоже работает — из float в int. Посмотрите на примере этого кода:
package main
import "fmt"
func main() {
var f float64 = 409.8
var i int = int(f)
fmt.Printf("f = %.3f\n", f)
fmt.Printf("i = %d\n", i)
}
В выводе будет два числа: f = 409.800 и i = 409. В первом случае программа выводит результат с тремя знаками после точки. Во втором случае функция сначала приводит float к int, а затем выводит цифры на экран. Все знаки после точки отбрасываются. Округление в большую или меньшую сторону не выполняется.
В Golang число в строку можно преобразовать с помощью метода strconv.Itoa. Он входит в состав пакета strconv стандартной библиотеки языка.
Выполните этот код:
package main
import (
"fmt"
"strconv"
)
func main() {
a := strconv.Itoa(12)
fmt.Printf("%q\n", a)
}
В итоге должна получиться строка — “12". Кавычки в выводе говорят о том, что это больше не число.
На практике такое преобразование строк и чисел часто используется для показа пользователям разной полезной информации. Например, вы делаете интернет-магазин. Разместили его на timeweb.cloud, реализовали основную бизнес-логику, наполнили товарами.
Через некоторое время после запуска пришел продакт-менеджер и предложил улучшить личный кабинет. Пользователь должен видеть, на какую сумму он совершил покупки и сколько ему осталось до получения следующего статуса. Для этого нужно выводить в личном кабинете сообщение, которое состоит из простого текста и набора цифр.
Попробуйте выполнить этот код:
package main
import (
"fmt"
)
func main() {
user := "Денис"
sum := 50
fmt.Println("Поздравляем, " + user + "! Вы потратили в нашем магазине уже " + lines + " рублей.")
}
В результате появится сообщение об ошибке. Выполнить конкатенацию строки и числа нельзя. Устранить ошибку поможет конвертирование данных в Golang.
Исправим код, преобразовав переменную lines в string:
package main
import (
"fmt"
"strconv"
)
func main() {
user := "Денис"
sum := 50
fmt.Println("Поздравляем, " + user + "! Вы потратили в нашем магазине уже " + strconv.Itoa(sum) + " рублей.")
}
Теперь ошибки не будет, в выводе отобразится правильный текст сообщения, в котором будет указан нужный набор цифр. Конечно, это упрощенный пример, в реальных проектах логика намного более ветвистая и трудная. Но знание базовых операций помогает избежать огромного количества ошибок. Особенно это важно при работе со сложными системами.
Вернемся к нашему примеру. Снова приходит продакт-менеджер и говорит, что покупатели хотят видеть в личном кабинете точную сумму покупок, вплоть до копеек. Целочисленное значение здесь не подходит. Как вы уже поняли из примеров выше, все знаки после точки просто отбрасываются. Чтобы сумма покупок в личном кабинете отражалась корректно, будем приводить к string не int, а float.
Для решения этой задачи есть метод fmt.Sprint, который входит в состав пакета fmt.
package main
import (
"fmt"
)
func main() {
fmt.Println(fmt.Sprint(421.034))
f := 5524.53
fmt.Println(fmt.Sprint(f))
}
Чтобы убедиться, что преобразование прошло успешно, соедините итог со строкой. Например:
package main
import (
"fmt"
)
func main() {
f := 5524.53
fmt.Println("Денис потратил " + fmt.Sprint(f) + " рублей.")
}
Ошибки нет, теперь в вашем информационном сообщении отображается число с плавающей точкой. Покупатели видят, сколько денег потратили в вашем магазине. Учтены все расходы с точностью до копейки.
Часто встречается и обратная задача — преобразовать string в числа. Допустим, у вас есть форма, в которой пользователь указывать возраст или любые другие числовые значения. Введенные данные сохраняются в формате string. Давайте попробуем с ними поработать — например, выполнить вычитание:
package main
import (
"fmt"
)
func main() {
lines_yesterday := "50"
lines_today := "108"
lines_more := lines_today - lines_yesterday
fmt.Println(lines_more)
}
Результатом выполнения этого кода будет сообщение об ошибке, так как вычитание не применяется к строковым значениям. Чтобы выполнять математические действия с данными, сохраненными в виде строк, необходимо привести их к int или float.
Выбор метода зависит от того, к какому типу вы будете приводить string. Если используется целое число, применяйте метод strconv.Atoi. Если передаете числа с плавающей точкой, применяйте метод strconv.ParseFloat.
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)
}
В этом примере вы используете оператор if для проверки того, удалось ли выполнить преобразование. Если произошла ошибка, то программа завершит работу, а информация об ошибке сохранится в логе. Если преобразование будет выполнено, то в выводе вы получите правильный результат: 108 - 50 = 58.
Если вы попробуете аналогичным образом преобразовать строку, внутри которой не численное значение, то получите сообщение об ошибке:
strconv.Atoi: parsing "not a number": invalid syntax
Попробуйте выполнить этот код:
package main
import (
"fmt"
"strconv"
)
func main() {
a := "not a number"
b, err := strconv.Atoi(a)
fmt.Println(b)
fmt.Println(err)
}
Код из примера выше не выполнится, так как вы пытаетесь преобразовать в числовой type строку, значением которой является не число.
Строки можно также преобразовывать в срезы байтов и обратно, используя конструкции []byte() и string().
package main
import (
"fmt"
)
func main() {
a := "timeweb"
b := []byte(a)
c := string(b)
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
В этой функции вы сохраняете string в переменную a, затем преобразуете эту же строку в срез байтов и сохраняете в переменную b, затем превращаете срез байтов в string и сохраняете результат в переменной c. Вывод будет таким:
timeweb
[116 105 109 101 119 101 98]
timeweb
Этот простой пример показывает, что можно без проблем конвертировать строки в срезы байтов и обратно.
Подготовили для вас выгодные тарифы на облачные серверы
В этой статье мы разобрали лишь основы. Посмотрели, какие есть типы данных, как выполняется в Golang приведение типов.
Если хотите узнать больше, изучите документацию языка или хотя бы учебник A Tour of Go — это интерактивное введение в Go в трех разделах. Первый раздел охватывает основной синтаксис и структуры данных, во второй части обсуждаются методы и интерфейсы, третий раздел представляет примитивы параллелизма Go. Каждая часть завершается несколькими упражнениями, чтобы вы могли попрактиковаться в том, что узнали.