1 Введение в типы данных языка Go

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

Тип данных Описание Используемая память
bool Логический тип, используется для хранения true или false 1 байт
int, uint Знаковые и беззнаковые целые числа, размер по умолчанию зависит от платформы системы 4 или 8 байт
int8, uint8 8-битные знаковые и беззнаковые целые числа 1 байт
int16, uint16 16-битные знаковые и беззнаковые целые числа 2 байта
int32, uint32 32-битные знаковые и беззнаковые целые числа 4 байта
int64, uint64 64-битные знаковые и беззнаковые целые числа 8 байт
float32 32-битное число с плавающей запятой 4 байта
float64 64-битное число с плавающей запятой 8 байт
complex64 Комплексное число с 32-битными действительной и мнимой частями 8 байт
complex128 Комплексное число с 64-битными действительной и мнимой частями 16 байт
byte Похож на uint8 1 байт
rune Похож на int32, представляющий кодовую точку Unicode 4 байта
string Строковый тип Зависит от длины строки
error Интерфейс ошибки, используется для возврата информации об ошибке Нет фиксированного размера

Эти типы могут быть выбраны в зависимости от различных потребностей, таких как числовые вычисления, обработка текста или логическое управление.

2 Типы данных целых чисел

2.1 Обзор типов целых чисел

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

  • Знаковые целые числа: int8, int16, int32 (или rune), int64 и int
  • Беззнаковые целые числа: uint8 (или byte), uint16, uint32, uint64 и uint

Размеры int и uint составляют 4 байта в 32-битных системах и 8 байт в 64-битных системах. Диапазоны значений типов данных целых чисел показаны в таблице ниже:

Тип Диапазон значений
int8 -128 до 127
uint8 0 до 255
int16 -32768 до 32767
uint16 0 до 65535
int32 -2147483648 до 2147483647
uint32 0 до 4294967295
int64 -9223372036854775808 до 9223372036854775807
uint64 0 до 18446744073709551615

2.2 Использование целочисленных переменных

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

var название_переменной тип_данных = начальное_значение

Пример кода:

package main
import "fmt"

func main() {
    var a int = 10 // Переменная знакового целого числа
    var b uint = 20 // Переменная беззнакового целого числа
    var c int8 = -128 // Наименьшее значение типа int8
    fmt.Println(a, b, c)
}

2.3 Операции с целыми числами

Язык Go поддерживает обычные арифметические операторы, такие как сложение (+), вычитание (-), умножение (*), деление (/) и взятие остатка (%), а также побитовые операторы, такие как побитовое И (&), ИЛИ (|), исключающее ИЛИ (^), побитовый сдвиг влево (<<) и побитовый сдвиг вправо (>>).

package main
import "fmt"

func main() {
    x := 10
    y := 3

    // Арифметические операции
    fmt.Println(x + y) // Сложение
    fmt.Println(x - y) // Вычитание
    fmt.Println(x * y) // Умножение
    fmt.Println(x / y) // Деление
    fmt.Println(x % y) // Остаток от деления

    // Побитовые операции
    fmt.Println(x & y)  // Побитовое И
    fmt.Println(x | y)  // Побитовое ИЛИ
    fmt.Println(x ^ y)  // Исключающее ИЛИ
    fmt.Println(x << 1) // Битовый сдвиг влево на 1
    fmt.Println(x >> 1) // Битовый сдвиг вправо на 1
}

3 Типы данных с плавающей запятой

3.1 Обзор типов данных с плавающей запятой

В языке Go типы данных с плавающей запятой включают float32 и float64, соответствующие 32-битным и 64-битным числам с плавающей запятой. В целом рекомендуется использовать float64, поскольку он обеспечивает более широкий диапазон и более точную точность.

  • float32 имеет приблизительно 23 значащих бита, обеспечивая около 7 десятичных цифр точности.
  • float64 имеет приблизительно 52 значащих бита, обеспечивая около 16 десятичных цифр точности.

3.2 Использование переменных с плавающей запятой

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

package main
import "fmt"

func main() {
    var f1 float32 = 3.14 // Явно указываем тип float32
    f2 := 3.14           // Автоматически выводится как тип float64
    fmt.Println(f1, f2)
}

3.3 Арифметика с плавающей запятой и проблемы

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

package main
import "fmt"

func main() {
    f1 := .1
    f2 := .2
    f3 := f1 + f2
    fmt.Println(f3) // Вывод может быть неожиданным .3 из-за потери точности

    // Исправление потери точности с помощью форматированного вывода
    fmt.Printf("%.1f\n", f3) // Вывод скорректирован до .3
}

4 Тип данных Boolean

4.1 Обзор типа Boolean

Boolean - самый простой тип данных, который может принимать только два значения: true (истина) и false (ложь). Он занимает очень важное положение в условных операторах и циклах.

4.2 Использование переменных типа Boolean

Объявление и использование булевых переменных:

package main
import "fmt"

func main() {
    var success bool = true
    var fail bool = false
    fmt.Println("Операция выполнена успешно:", success)
    fmt.Println("Операция завершилась неудачей:", fail)
}

Значения типа Boolean часто используются в условных операторах:

package main
import "fmt"

func main() {
    a := 10
    b := 20
    fmt.Println("a == b:", a == b) // false
    fmt.Println("a < b:", a < b)   // true
}

5 Тип данных String

5.1 Обзор строк

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

5.2 Использование строковых переменных

Обычно строковые переменные объявляются с использованием двойных кавычек " для создания, но также можно использовать обратные кавычки ` для создания строк с несколькими строками:

package main
import "fmt"

func main() {
    var s1 string = "привет"
    s2 := "мир"
    s3 := `Это
    строка с
    несколькими строками`
    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
}

После создания строки её содержимое изменить нельзя. Следующая операция недопустима и приведет к ошибке компиляции:

s := "привет"
s[] = 'П` // Ошибка компиляции: содержимое строки неизменно

5.3 Операции со строками

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

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

В языке Go можно использовать оператор плюс (+) для конкатенации строк, что является самым простым способом. Кроме того, при работе с частой конкатенацией нескольких строк рекомендуется использовать strings.Builder для более эффективной производительности.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // Конкатенация строк с использованием +
    hello := "Привет, "
    world := "Мир!"
    result := hello + world
    fmt.Println(result) // Вывод: Привет, Мир!

    // Конкатенация строк с использованием strings.Builder
    var sb strings.Builder
    sb.WriteString("Привет, ")
    sb.WriteString("Мир!")
    fmt.Println(sb.String()) // Вывод: Привет, Мир!
}

5.3.2 Разделение строки

Разделение строк можно выполнить с помощью функции strings.Split, которая разбивает строку на сегменты на основе указанного разделителя.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // Определение строки
    sentence := "Go - это язык программирования с открытым исходным кодом"

    // Разбиваем строку по пробелу
    words := strings.Split(sentence, " ")
    for _, word := range words {
        fmt.Printf("%s\n", word)
    }
    // Вывод:
    // Go
    // это
    // язык
    // программирования
    // с
    // открытым
    // исходным
    // кодом
}

5.3.3 Доступ к индексу

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

package main

import "fmt"

func main() {
    s := "Привет, мир"
    for i := 0; i < len(s); i++ {
        fmt.Printf("%d: %x\n", i, s[i])
    }
    // Примечание: это выведет шестнадцатеричное представление байтов, а не символов
}

Для перебора строки по символам, вы можете использовать цикл range.

package main

import "fmt"

func main() {
    s := "Привет, мир"
    for index, runeValue := range s {
        fmt.Printf("%d: %U '%c'\n", index, runeValue, runeValue)
    }
    // Вывод: индекс, кодировка Unicode и сам символ для каждого символа
}

5.3.4 Получение длины

Функция len может получить длину строки, то есть длину базовой последовательности байтов. Для UTF-8 строк, если вам нужно получить количество символов (символов Unicode), вы должны использовать функцию utf8.RuneCountInString. Она правильно обрабатывает многобайтовые символы.

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "Привет, мир"
    fmt.Println("Длина байтов:", len(s)) // Вывод длины в байтах
    fmt.Println("Длина символов:", utf8.RuneCountInString(s)) // Вывод длины символов
}

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