Изучение базовых типов данных

Завершено

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

В Go есть четыре категории типов данных:

  • базовые типы — числа, строки и логические значения;
  • агрегатные типы — массивы и структуры;
  • ссылочные типы — указатели, срезы, карты, функции и каналы;
  • интерфейсные типы — интерфейсы.

В этом модуле затрагиваются только базовые типы. Не беспокойтесь, если вы не знакомы с другими типами. Они будут рассматриваться в будущих модулях.

Начнем с изучения числовых типов данных.

Целые числа

В общих чертах, для определения целочисленного типа служит ключевое слово int. Но в Go также доступны типы int8, int16, int32 и int64, которые являются целыми числами размером 8, 16, 32 или 64 бита, соответственно. В 32-разрядной операционной системе, если вы используете int, то размер обычно составляет 32 бита. В 64-разрядных системах размер int обычно составляет 64 бита. Однако это поведение на разных компьютерах может различаться. Вы можете использовать uint. Однако используйте этот тип, только если по какой-то причине вам необходимо представить значение как число без знака. Go также предоставляет типы uint8, uint16, uint32 и uint64.

Ниже приведен пример использования различных целочисленных типов в Go:

var integer8 int8 = 127
var integer16 int16 = 32767
var integer32 int32 = 2147483647
var integer64 int64 = 9223372036854775807
fmt.Println(integer8, integer16, integer32, integer64)

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

var integer16 int16 = 127
var integer32 int32 = 32767
fmt.Println(integer16 + integer32)

При запуске программы произойдет следующая ошибка:

invalid operation: integer16 + integer32 (mismatched types int16 and int32)

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

По мере изучения Go вы, возможно, встретитесь с термином руны. rune — это просто псевдоним для типа данных int32. Он используется для представления символа Юникода (или кодовой точки Юникода). Предположим, что у вас есть следующий код:

rune := 'G'
fmt.Println(rune)

При выполнении приведенного выше фрагмента кода вы ожидаете, что программа выведет G в командной строке. Но отображается число 71, представляющее символ Юникода для G. Мы поговорим о рунах в последующих модулях.

Сведения о диапазонах для каждого типа можно найти на странице с исходным кодом Go . Знание диапазонов каждого типа будет полезно для выбора правильного типа данных, а также позволит избежать нерационального использования памяти.

Задание 1

Задайте другую переменную типа int и используйте значение из переменной integer32 или integer64 для подтверждения естественного размера переменной в системе. Если вы работаете в 32-разрядной системе и используете значение выше 2 147 483 647, возникнет ошибка переполнения, которая выглядит следующим образом: constant 9223372036854775807 overflows int.

Решение проблемы:

package main

import "fmt"

func main() {
   var integer32 int = 2147483648
   fmt.Println(integer32)
}

Задание 2

Объявите переменную без знака, например uint, и инициализируйте ее отрицательным значением, например -10. При попытке запустить программу должна появиться ошибка следующего вида: constant -10 overflows uint.

Решение проблемы:

package main

import "fmt"

func main() {
   var integer uint = -10
   fmt.Println(integer)
}

Числа с плавающей запятой

Go предоставляет типы данных для двух размеров чисел с плавающей запятой: float32 и float64. Эти типы можно использовать, если требуется хранить большие числа и они не помещаются ни в одном из упомянутых ранее целочисленных типов. Разница между этими двумя типами заключается в максимальном размере битов, которые они могут хранить. Чтобы узнать, как использовать эти два типа, взгляните на следующие строки:

var float32 float32 = 2147483647
var float64 float64 = 9223372036854775807
fmt.Println(float32, float64)

Ограничения этих двух типов можно найти с помощью констант math.MaxFloat32 и math.MaxFloat64, доступных в пакете math. Используйте следующий код, чтобы вывести в командной строке максимальное число значений с плавающей запятой:

package main

import (
    "fmt"
    "math"
)    

func main() {
    fmt.Println(math.MaxFloat32, math.MaxFloat64)
}

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

const e = 2.71828
const Avogadro = 6.02214129e23
const Planck = 6.62606957e-34

Обратите внимание, что с помощью предыдущего кода Go выводит типы данных из используемых значений.

Логические значения

Логический тип имеет только два возможных значения: true и false. Логический тип объявляется с помощью ключевого слова bool. Go отличается от других языков программирования. В Go нельзя неявно преобразовать логический тип в 0 или 1. Это необходимо делать явным образом.

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

var featureFlag bool = true

Мы будем использовать логические типы данных в последующем модуле, когда будем говорить об операторах потока управления в Go. Мы будем применять их в последующих модулях.

Строки

Наконец, рассмотрим наиболее распространенный тип данных в любом языке программирования — строковой. Для представления строкового типа данных в Go используется ключевое слово string. Чтобы инициализировать строковую переменную, необходимо определить ее значение внутри двойных кавычек ("). Одинарные кавычки (') используются для отдельных символов (и для рун, как мы видели в предыдущем разделе).

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

var firstName string = "John"
lastName := "Doe"
fmt.Println(firstName, lastName)

Иногда требуется экранировать символы. Чтобы сделать это в Go, добавьте перед символом обратную косую черту (\). Ниже приведены наиболее распространенные примеры использования escape-символов.

  • \n для новых строк
  • \r для возвратов каретки
  • \t для вкладок
  • \' для одинарных кавычек
  • \" для двойных кавычек
  • \\ для обратных косых черт

Используйте следующий фрагмент кода для проверки escape-символов:

fullName := "John Doe \t(alias \"Foo\")\n"
fmt.Println(fullName)

Вы должны увидеть следующий результат (включая новую строку):

John Doe        (alias "Foo")

Значения по умолчанию

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

Ниже приведен список нескольких значений по умолчанию для уже рассмотренных нами типов.

  • 0 для типов int (и всех его подтипов, например int64)
  • +0.000000e+000 для типов float32 и float64
  • false для типов bool
  • Пустое значение для типов string

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

var defaultInt int
var defaultFloat32 float32
var defaultFloat64 float64
var defaultBool bool
var defaultString string
fmt.Println(defaultInt, defaultFloat32, defaultFloat64, defaultBool, defaultString)

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

Преобразование типов

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

var integer16 int16 = 127
var integer32 int32 = 32767
fmt.Println(int32(integer16) + integer32)

Другой вариант для приведения в Go — использование пакета strconv. Например, чтобы преобразовать string в int и наоборот, можно использовать следующий код:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    i, _ := strconv.Atoi("-42")
    s := strconv.Itoa(-42)
    fmt.Println(i, s)
}

Выполните приведенный выше код и убедитесь, что он выполняется и выводит -42 два раза.

Обратите внимание, что в этом коде в качестве имени переменной используется символ подчеркивания (_). В Go означает, _ что мы не будем использовать значение этой переменной, и что мы хотим игнорировать ее. В противном случае программа не будет компилироваться, так как нужно использовать все объявленные переменные. Мы вернемся к этой теме, и вы узнаете, что _ обычно представляет в предстоящих модулях.