4.1 Массивы в Go: основы

Массивы в Go является структурой фиксированный длины, которая содержит элементы одного типа.

Объявление массива

// массив можно объявить через var, например, массив из 5 элементов типа int, по умолчанию инициализируются нулями
var a [5]int 
fmt.Println(a) // [0 0 0 0 0]

// также можно инициализировать массив при объявлении, например, массив из 3 элементов типа int
b := [3]int{1, 2, 3}
fmt.Println(b) // [1, 2, 3]

// Можно использовать краткую форму объявления массива, которая автоматически определит длину на этапе компиляции
c := [...]int{10, 20, 30}
fmt.Println(c) // [10 20 30]

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

В памяти массив из 5-и byte элементов будет выглядеть следующим образом:

Массив a: [5]byte{1, 2, 3, 4, 5}

Память:
+----+----+----+----+----+
|  1 |  2 |  3 |  4 |  5 |
+----+----+----+----+----+
Индексы:
  0    1    2    3    4

Рассмотрим основные операции с массивами

Нумерация элементов массива начинается с 0

a := [5]byte{1, 2, 3, 4, 5}

// обращение к элементу массива
fmt.Println(a[0]) // 1 
fmt.Println(a[4]) // 5

// если обратиться к элементу массива вне диапазона, то по сути мы попытаемся получить чужую область памяти, на практике это приведет к панике
fmt.Println(b[5]) // panic: index out of range

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

a := [5]byte{1, 2, 3, 4, 5}

// Получить длину массива
len(a) // 5

//Получить вместимость массива
cap(a) // 5

Так как массивы являются фиксированными по длине, то для них не поддерживается функция append.

Итерирование по элементам массива

package main

import "fmt"

func main() {
	a := [4]int64{111, 222, 333, 444}
	for i, v := range a {
		fmt.Printf("index %d: value %d \n", i, v)
	}
}


// Выведет
index 0: value 111 
index 1: value 222 
index 2: value 333 
index 3: value 444 

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

package main

import "fmt"

func main() {
	a := [4]int64{111, 222, 333, 444}
	for i, v := range a {
		a[3] = 777 // пытаемся изменить 3-ий элемент массива
		fmt.Printf("index %d: value %d \n", i, v)
	}

	fmt.Println(a)
}
// Внутри цикла значения такие же как и при инициализации
// index 0: value 111 
// index 1: value 222 
// index 2: value 333 
// index 3: value 444 

// При этом исходный массив мы изменили
// [111 222 333 777]

Копирование массивов

Прямого копирования массивов в Go нет, но при этом мы можем привести массив к срезу

package main

import "fmt"

func main() {
    var src [3]int = [3]int{1, 2, 3}
    var dst [3]int

    // Приведение массивов к срезам
    copy(dst[:], src[:])

    fmt.Println("Исходный массив:", src) // Исходный массив: [1 2 3]
    fmt.Println("Целевой массив:", dst) // Целевой массив: [1 2 3]
}

Не будем останавилваться на различиях slice и array, так как этому будет посвящен следующий раздел.

Сравнение массивов

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

package main

import "fmt"

func main() {
    a := [3]int{1, 2, 3}
    b := [3]int{1, 2, 3}
    c := [3]int{4, 5, 6}

    fmt.Println("a == b:", a == b) // true
    fmt.Println("a == c:", a == c) // false
}

Мы рассмотрели основные операции при работе с массивами, в следующих главах мы рассмотрим устройство массивов более детально.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *