Массивы и слайсы
Что такое массив в Go?
В языке программирования Go массив — это структура данных, которая представляет собой фиксированную последовательность элементов одного типа. Размер массива задается при его создании и не может изменяться в дальнейшем. Элементы массива индексируются, начиная с нуля.
Пример объявления и использования массива в Go:
package main
import "fmt"
func main() {
// Объявление массива из 5 целых чисел
var numbers [5]int
// Инициализация элементов массива
numbers[0] = 10
numbers[1] = 20
numbers[2] = 30
numbers[3] = 40
numbers[4] = 50
// Вывод элементов массива
for i := 0; i < len(numbers); i++ {
fmt.Println(numbers[i])
}
}
В этом примере создается массив numbers
из 5 целых чисел, инициализируются его элементы и выводятся на экран.
Что такое слайс в Go?
Слайс в Go — это структура данных, которая представляет собой динамический массив. В отличие от массивов, слайсы могут изменять свой размер во время выполнения программы. Слайсы являются более гибкими и удобными для работы с последовательностями данных.
Слайс состоит из трех компонентов:
Указатель на массив, который хранит элементы.
Длина (количество элементов в слайсе).
Емкость (максимальное количество элементов, которые могут быть размещены в слайсе без выделения новой памяти).
Пример объявления и использования слайса в Go:
package main
import "fmt"
func main() {
// Объявление и инициализация слайса
numbers := []int{10, 20, 30, 40, 50}
// Добавление элементов в слайс
numbers = append(numbers, 60, 70)
// Вывод элементов слайса
for i := 0; i < len(numbers); i++ {
fmt.Println(numbers[i])
}
// Вывод длины и емкости слайса
fmt.Printf("Length: %d, Capacity: %d\n", len(numbers), cap(numbers))
}
В этом примере создается слайс numbers
, инициализируется несколькими значениями, затем в него добавляются новые элементы с помощью функции append
. После этого элементы слайса выводятся на экран, а также выводятся его длина и емкость.
Чем слайс отличается от массива?
В отличие от массива, который представляет фиксированную по размеру коллекцию данных, слайс в GoLang является более гибкой структурой, позволяющей изменять свою длину. Слайс создает массив, который может изменять свой размер, в то время как массив имеет фиксированную длину. Поэтому, слайс в GoLang является надмножеством массивов, обеспечивая большую гибкость при работе с данными.
Как сконвертировать массив в слайс в golang?
Для конвертации массива в слайс в Golang можно использовать следующий подход:
array := [5]int{1, 2, 3, 4, 5}
slice := array[:]
Здесь:
array
- массив из 5 целых чиселslice := array[:]
создает слайс, который ссылается на тот же массив данных, что иarray
[1][4]
Другой способ создать слайс из массива - явно указать длину и емкость:
array := [5]int{1, 2, 3, 4, 5}
slice := array[:3:4]
Это создаст слайс длиной 3 и емкостью 4, ссылающийся на первые 3 элемента массива array
[1].
Важно понимать, что слайс не копирует данные массива, а создает ссылку на те же данные. Изменение элементов слайса повлияет на соответствующие элементы исходного массива[4].
Таким образом, для конвертации массива в слайс в Golang достаточно создать слайс, используя оператор среза [:]
и указав массив в качестве операнда слева.
Citations: [1] https://golangify.com/convert-types [2] https://folko.gitbook.io/goland/voprosy-sobesedovaniya/bazovye-voprosy-po-golang [3] https://habr.com/ru/companies/vk/articles/574542/ [4] https://golangify.com/string [5] https://www.nic.ru/help/samye-rasprostranennye-tipy-dannyh-v-go-v-chem-raznica_11652.html
Важные моменты
Срезы в Go являются ссылочными типами, что означает, что они указывают на оригинальный массив. Изменения в срезе отражаются на массиве и наоборот.
Если вы изменяете размер среза так, что он выходит за пределы исходного массива, Go автоматически выделит новый участок памяти для размещения данных среза. Это важно для понимания производительности и управления памятью.
В каком случае меняется размер слайса Go?
В Go слайсы являются динамическими массивами, которые могут изменять свой размер. Размер слайса может изменяться в следующих случаях:
1. При использовании функции append
append
Функция append
добавляет элементы в слайс и может изменять его размер. Если емкость (capacity) слайса недостаточна для добавления новых элементов, создается новый массив с увеличенной емкостью, и элементы копируются в него.
Пример:
package main
import "fmt"
func main() {
s := []int{1, 2, 3}
fmt.Println("Before append:", s, "len:", len(s), "cap:", cap(s))
s = append(s, 4, 5)
fmt.Println("After append:", s, "len:", len(s), "cap:", cap(s))
}
Вывод:
Before append: [1 2 3] len: 3 cap: 3
After append: [1 2 3 4 5] len: 5 cap: 6
2. При срезе (slicing)
Создание нового слайса путем среза существующего слайса может изменить его размер, но не емкость. Новый слайс будет ссылаться на тот же массив, что и исходный слайс.
Пример:
package main
import "fmt"
func main() {
s := []int{1, 2, 3, 4, 5}
fmt.Println("Original slice:", s, "len:", len(s), "cap:", cap(s))
s2 := s[1:4]
fmt.Println("Sliced slice:", s2, "len:", len(s2), "cap:", cap(s2))
}
Вывод:
Original slice: [1 2 3 4 5] len: 5 cap: 5
Sliced slice: [2 3 4] len: 3 cap: 4
3. При использовании функции copy
copy
Функция copy
копирует элементы из одного слайса в другой. Если целевой слайс имеет меньший размер, чем исходный, копируются только те элементы, которые помещаются в целевой слайс.
Пример:
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4, 5}
dst := make([]int, 3)
fmt.Println("Before copy:", dst, "len:", len(dst), "cap:", cap(dst))
copy(dst, src)
fmt.Println("After copy:", dst, "len:", len(dst), "cap:", cap(dst))
}
Вывод:
Before copy: [0 0 0] len: 3 cap: 3
After copy: [1 2 3] len: 3 cap: 3
4. При использовании функции append
с срезом
append
с срезомВы можете использовать append
для добавления элементов из одного слайса в другой. Это также может изменить размер целевого слайса.
Пример:
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5, 6}
fmt.Println("Before append:", s1, "len:", len(s1), "cap:", cap(s1))
s1 = append(s1, s2...)
fmt.Println("After append:", s1, "len:", len(s1), "cap:", cap(s1))
}
Вывод:
Before append: [1 2 3] len: 3 cap: 3
After append: [1 2 3 4 5 6] len: 6 cap: 6
Заключение
Размер слайса в Go может изменяться при использовании функции append
, при создании нового слайса путем среза, при копировании элементов с помощью функции copy
, а также при добавлении элементов из одного слайса в другой с помощью append
. Эти операции позволяют гибко управлять размером и содержимым слайсов, что делает их мощным инструментом для работы с динамическими массивами в Go.
В каких случаях append создает копию слайса?
Функция append
в Go может создавать копию слайса в определенных случаях, связанных с емкостью (capacity) исходного слайса. Понимание этих случаев важно для эффективного управления памятью и производительности.
Когда append
создает копию слайса
append
создает копию слайсаНедостаточная емкость (capacity):
Если емкость исходного слайса недостаточна для размещения новых элементов,
append
создает новый массив с увеличенной емкостью и копирует в него элементы исходного слайса. Новый массив затем используется для хранения добавленных элементов.
Пример:
package main
import "fmt"
func main() {
s := make([]int, 3, 3) // len=3, cap=3
s[0], s[1], s[2] = 1, 2, 3
fmt.Println("Before append:", s, "len:", len(s), "cap:", cap(s))
s = append(s, 4) // Недостаточная емкость, создается новый массив
fmt.Println("After append:", s, "len:", len(s), "cap:", cap(s))
}
Вывод:
Before append: [1 2 3] len: 3 cap: 3
After append: [1 2 3 4] len: 4 cap: 6
Когда append
не создает копию слайса
append
не создает копию слайсаДостаточная емкость (capacity):
Если емкость исходного слайса достаточна для размещения новых элементов,
append
просто добавляет элементы в существующий массив, не создавая новый массив.
Пример:
package main
import "fmt"
func main() {
s := make([]int, 3, 5) // len=3, cap=5
s[0], s[1], s[2] = 1, 2, 3
fmt.Println("Before append:", s, "len:", len(s), "cap:", cap(s))
s = append(s, 4) // Достаточная емкость, новый массив не создается
fmt.Println("After append:", s, "len:", len(s), "cap:", cap(s))
}
Вывод:
Before append: [1 2 3] len: 3 cap: 5
After append: [1 2 3 4] len: 4 cap: 5
Пример с проверкой изменения адреса массива
Для наглядности можно проверить, изменился ли адрес массива после вызова append
. Если адрес изменился, значит, был создан новый массив.
Пример:
package main
import (
"fmt"
"unsafe"
)
func main() {
s := make([]int, 3, 3) // len=3, cap=3
s[0], s[1], s[2] = 1, 2, 3
fmt.Printf("Before append: %v, len: %d, cap: %d, address: %p\n", s, len(s), cap(s), unsafe.Pointer(&s[0]))
s = append(s, 4) // Недостаточная емкость, создается новый массив
fmt.Printf("After append: %v, len: %d, cap: %d, address: %p\n", s, len(s), cap(s), unsafe.Pointer(&s[0]))
}
Вывод:
Before append: [1 2 3], len: 3, cap: 3, address: 0xc0000140a0
After append: [1 2 3 4], len: 4, cap: 6, address: 0xc0000140c0
Заключение
Функция append
в Go создает копию слайса, когда емкость исходного слайса недостаточна для размещения новых элементов. В этом случае создается новый массив с увеличенной емкостью, и элементы исходного слайса копируются в него. Если емкость исходного слайса достаточна, append
просто добавляет элементы в существующий массив, не создавая новый массив. Понимание этих механизмов помогает эффективно управлять памятью и производительностью при работе со слайсами в Go.
Last updated