Перейти к курсу: Массивы и фрагменты

В этом уроке мы узнаем о массивах и срезах в Go.

Массивы

Что же такое массив?

Массив — это коллекция элементов фиксированного размера одного типа. Элементы массива хранятся последовательно, и доступ к ним можно получить по их index.

Объявление

Мы можем объявить массив следующим образом:

var a [n]T
Войти в полноэкранный режим Выйти из полноэкранного режима

Здесь n — это длина, а T может быть любым типом, например, целым числом, строкой или пользовательской структурой.

Теперь объявим массив целых чисел длиной 4 и выведем его на печать.

func main() {
    var arr [4]int

    fmt.Println(arr)
}
Войти в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
[0 0 0 0]
Войти в полноэкранный режим Выйти из полноэкранного режима

По умолчанию все элементы массива инициализируются нулевым значением соответствующего типа массива.

Инициализация

Мы также можем инициализировать массив с помощью литерала массива.

var a [n]T = [n]T{V1, V2, ... Vn}
Вход в полноэкранный режим Выход из полноэкранного режима
func main() {
    var arr = [4]int{1, 2, 3, 4}

    fmt.Println(arr)
}
Войти в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
[1 2 3 4]
Войти в полноэкранный режим Выход из полноэкранного режима

Мы можем даже сделать сокращенное объявление.

...
arr := [4]int{1, 2, 3, 4}
Ввести полноэкранный режим Выход из полноэкранного режима

Доступ к

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

func main() {
    arr := [4]int{1, 2, 3, 4}

    fmt.Println(arr[0])
}
Войти в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
1
Войти в полноэкранный режим Выход из полноэкранного режима

Итерация

Теперь поговорим об итерации.

Итак, существует несколько способов итерации массивов.

Первый — это использование цикла for с функцией len, которая выдает нам длину массива.

func main() {
    arr := [4]int{1, 2, 3, 4}

    for i := 0; i < len(arr); i++ {
        fmt.Printf("Index: %d, Element: %dn", i, arr[i])
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
Index: 0, Element: 1
Index: 1, Element: 2
Index: 2, Element: 3
Index: 3, Element: 4
Войти в полноэкранный режим Выход из полноэкранного режима

Другой способ — использовать ключевое слово range с циклом for.

func main() {
    arr := [4]int{1, 2, 3, 4}

    for i, e := range arr {
        fmt.Printf("Index: %d, Element: %dn", i, e)
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
Index: 0, Element: 1
Index: 1, Element: 2
Index: 2, Element: 3
Index: 3, Element: 4
Войти в полноэкранный режим Выход из полноэкранного режима

Как мы видим, наш пример работает так же, как и раньше.

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

for i, e := range arr {} // Normal usage of range

for _, e := range arr {} // Omit index with _ and use element

for i := range arr {} // Use index only

for range arr {} // Simply loop over the array
Войти в полноэкранный режим Выход из полноэкранного режима

Многомерность

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

Давайте рассмотрим пример:

func main() {
    arr := [2][4]int{
        {1, 2, 3, 4},
        {5, 6, 7, 8},
    }

    for i, e := range arr {
        fmt.Printf("Index: %d, Element: %dn", i, e)
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
Index: 0, Element: [1 2 3 4]
Index: 1, Element: [5 6 7 8]
Войти в полноэкранный режим Выход из полноэкранного режима

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

func main() {
    arr := [...][4]int{
        {1, 2, 3, 4},
        {5, 6, 7, 8},
    }

    for i, e := range arr {
        fmt.Printf("Index: %d, Element: %dn", i, e)
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
Index: 0, Element: [1 2 3 4]
Index: 1, Element: [5 6 7 8]
Войти в полноэкранный режим Выход из полноэкранного режима

Свойства

Теперь поговорим о некоторых свойствах массивов.

Длина массива является частью его типа. Так, массивы a и b являются совершенно разными типами, и мы не можем присвоить один другому.

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

package main

func main() {
    var a = [4]int{1, 2, 3, 4}
    var b [2]int = a // Error, cannot use a (type [4]int) as type [2]int in assignment
}
Вход в полноэкранный режим Выход из полноэкранного режима

Массивы в Go являются типами значений, в отличие от других языков, таких как C, C++ и Java, где массивы являются ссылочными типами.

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

Таким образом, если мы вносим какие-либо изменения в этот скопированный массив, исходный массив не будет затронут и останется неизменным.

package main

import "fmt"

func main() {
    var a = [7]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
    var b = a // Copy of a is assigned to b

    b[0] = "Monday"

    fmt.Println(a) // Output: [Mon Tue Wed Thu Fri Sat Sun]
    fmt.Println(b) // Output: [Monday Tue Wed Thu Fri Sat Sun]
}
Вход в полноэкранный режим Выход из полноэкранного режима

Слайсы

Я знаю, о чем вы думаете: массивы полезны, но немного негибки из-за ограничений, вызванных их фиксированным размером.

Это приводит нас к Slice, так что же такое срез?

Слайс — это сегмент массива. Слайсы основываются на массивах и обеспечивают большую мощность, гибкость и удобство.

Слайс состоит из трех частей:

  • Указатель на базовый массив.
  • Длина сегмента массива, который содержит фрагмент.
  • И емкости, которая представляет собой максимальный размер, до которого может вырасти сегмент.

Подобно функции len, мы можем определить емкость фрагмента с помощью встроенной функции cap. Вот пример:

package main

import "fmt"

func main() {
    a := [5]int{20, 15, 5, 30, 25}

    s := a[1:4]

    // Output: Array: [20 15 5 30 25], Length: 5, Capacity: 5
    fmt.Printf("Array: %v, Length: %d, Capacity: %dn", a, len(a), cap(a))

    // Output: Slice [15 5 30], Length: 3, Capacity: 4
    fmt.Printf("Slice: %v, Length: %d, Capacity: %d", s, len(s), cap(s))
}
Вход в полноэкранный режим Выход из полноэкранного режима

Не волнуйтесь, мы подробно обсудим все, что здесь показано.

Объявление

Давайте посмотрим, как мы можем объявить фрагмент.

var s []T
Вход в полноэкранный режим Выйти из полноэкранного режима

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

func main() {
    var s []string

    fmt.Println(s)
    fmt.Println(s == nil)
}
Вход в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
[]
true
Вход в полноэкранный режим Выход из полноэкранного режима

Итак, в отличие от массивов, нулевым значением среза является nil.

Инициализация

Существует несколько способов инициализации нашего среза. Один из способов — использовать встроенную функцию make.

make([]T, len, cap) []T
Вход в полноэкранный режим Выход из полноэкранного режима
func main() {
var s = make([]string, 0, 0)

    fmt.Println(s)
}
Войти в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
[]
Вход в полноэкранный режим Выход из полноэкранного режима

Подобно массивам, мы можем использовать литерал slice для инициализации нашего среза.

func main() {
    var s = []string{"Go", "TypeScript"}

    fmt.Println(s)
}
Вход в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
[Go TypeScript]
Войти в полноэкранный режим Выход из полноэкранного режима

Другой способ — создать фрагмент из массива. Поскольку срез — это сегмент массива, мы можем создать срез от индекса low до high следующим образом.

a[low:high]
Войти в полноэкранный режим Выход из полноэкранного режима
func main() {
    var a = [4]string{
        "C++",
        "Go",
        "Java",
        "TypeScript",
    }

    s1 := a[0:2] // Select from 0 to 2
    s2 := a[:3]  // Select first 3
    s3 := a[2:]  // Select last 2

    fmt.Println("Array:", a)
    fmt.Println("Slice 1:", s1)
    fmt.Println("Slice 2:", s2)
    fmt.Println("Slice 3:", s3)
}
Войти в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
Array: [C++ Go Java TypeScript]
Slice 1: [C++ Go]
Slice 2: [C++ Go Java]
Slice 3: [Java TypeScript]
Войти в полноэкранный режим Выход из полноэкранного режима

Отсутствие младшего индекса означает 0, а отсутствие старшего индекса означает len(a).

Здесь следует отметить, что мы можем создавать срезы из других срезов, а не только из массивов.

    var a = []string{
        "C++",
        "Go",
        "Java",
        "TypeScript",
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Итерация

Мы можем выполнять итерацию по фрагменту так же, как и по массиву, используя цикл for с функцией len или ключевым словом range.

Функции

Итак, теперь поговорим о встроенных функциях для работы с фрагментами, предоставляемых в Go.

  • copy

Функция copy() копирует элементы из одного фрагмента в другой. Она принимает 2 фрагмента, конечный и исходный. Она также возвращает количество скопированных элементов.

func copy(dst, src []T) int
Вход в полноэкранный режим Выход из полноэкранного режима

Давайте посмотрим, как мы можем ее использовать.

func main() {
    s1 := []string{"a", "b", "c", "d"}
    s2 := make([]string, len(s1))

    e := copy(s2, s1)

    fmt.Println("Src:", s1)
    fmt.Println("Dst:", s2)
    fmt.Println("Elements:", e)
}
Войти в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
Src: [a b c d]
Dst: [a b c d]
Elements: 4
Войти в полноэкранный режим Выход из полноэкранного режима

Как и ожидалось, наши 4 элемента из исходного фрагмента были скопированы в целевой фрагмент.

  • добавление

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

Она принимает фрагмент и переменное количество аргументов. Затем она возвращает новый фрагмент, содержащий все элементы.

append(slice []T, elems ...T) []T
Вход в полноэкранный режим Выход из полноэкранного режима

Давайте попробуем это на примере, добавив элементы к нашему фрагменту.

func main() {
    s1 := []string{"a", "b", "c", "d"}

    s2 := append(s1, "e", "f")

    fmt.Println("s1:", s1)
    fmt.Println("s2:", s2)
}
Вход в полноэкранный режим Выход из полноэкранного режима
$ go run main.go
s1: [a b c d]
s2: [a b c d e f]
Войти в полноэкранный режим Выход из полноэкранного режима

Как мы видим, новые элементы были добавлены, и был возвращен новый фрагмент.

Но если данный фрагмент не имеет достаточной емкости для новых элементов, то выделяется новый базовый массив с большей емкостью.

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

Свойства

Наконец, давайте обсудим некоторые свойства срезов.

В отличие от массивов, срезы являются ссылочными типами.

Это означает, что изменение элементов фрагмента приведет к изменению соответствующих элементов в массиве, на который ссылается фрагмент.

package main

import "fmt"

func main() {
    a := [7]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}

    s := a[0:2]

    s[0] = "Sun"

    fmt.Println(a) // Output: [Sun Tue Wed Thu Fri Sat Sun]
    fmt.Println(s) // Output: [Sun Tue]
}
Вход в полноэкранный режим Выход из полноэкранного режима

Ломтики можно использовать и с переменными типами.

package main

import "fmt"

func main() {
    values := []int{1, 2, 3}
    sum := add(values...)
    fmt.Println(sum)
}

func add(values ...int) int {
    sum := 0
    for _, v := range values {
        sum += v
    }

    return sum
}
Вход в полноэкранный режим Выход из полноэкранного режима

Эта статья является частью моего открытого курса по Go, доступного на Github.

karanpratapsingh / go-course

Освойте основы и расширенные возможности языка программирования Go

Курс по Go

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

Этот курс также доступен на моем сайте, а также на Educative.io

Оглавление

  • Начало работы

    • Что такое Go?
    • Зачем изучать Go?
    • Установка и настройка
  • Глава I

    • Hello World
    • Переменные и типы данных
    • Форматирование строк
    • Управление потоком данных
    • Функции
    • Модули
    • Пакеты
    • Рабочие пространства
    • Полезные команды
    • Сборка
  • Глава II

    • Указатели
    • Структуры
    • Методы
    • Массивы и фрагменты
    • Карты
  • Глава III

    • Интерфейсы
    • Ошибки
    • Паника и восстановление
    • Тестирование
    • Дженерики
  • Глава IV

    • Параллелизм
    • Гороутины
    • Каналы
    • Выбрать
    • Пакет синхронизации
    • Расширенные шаблоны параллелизма
    • Контекст
  • Приложение

    • Следующие шаги
    • Ссылки

Что такое Go?

Go (также известный как Golang) — это язык программирования, разработанный в Google в 2007 году и открытый в 2009 году.

Основное внимание в нем уделяется простоте, надежности и эффективности. Он был разработан, чтобы объединить эффективность, скорость и безопасность статически типизированного и компилируемого языка с легкостью…

Посмотреть на GitHub

Оцените статью
devanswers.ru
Добавить комментарий