- PVSM.RU - https://www.pvsm.ru -
Перевод статьи подготовлен специально для студентов курса «Разработчик Golang» [1], занятия по которому начинаются уже сегодня!
В этой статье мы рассмотрим их различия и реализации в Go.
Мы обратимся к примерам, чтобы вы могли принимать более взвешенное решение о том, где их применять.
Массив – это коллекция фиксированного размера. Акцент здесь ставится именно на фиксированный размер, поскольку, как только вы зададите длину массива, позже вы уже не сможете ее изменить.
Давайте рассмотрим пример. Мы создадим массив из четырех целых значений:
arr := [4]int{3, 2, 5, 4}
В примере выше переменная arr
определена как массив типа [4]int
, это означает, что массив состоит из четырех элементов. Важно обратить внимание на то, что размер 4
включен в определение типа.
Из этого исходит, что на самом деле массивы разной длины — это массивы разных типов. Вы не сможете приравнять друг к другу массивы разной длины и не сможете присвоить значение одного массива другому в таком случае:
longerArr := [5]int{5, 7, 1, 2, 0}
longerArr = arr
// This gives a compilation error
longerArr == arr
// This gives a compilation error
Я обнаружил, что о массивах легко рассуждать с точки зрения структур. Если бы вы попытались создать структуру подобную массиву, у вас скорее всего получилось бы следующее:
// Struct equivalent for an array of length 4
type int4 struct {
e0 int
e1 int
e2 int
e3 int
}
// Struct equivalent for an array of length 5
type int5 struct {
e0 int
e1 int
e2 int
e3 int
e5 int
}
arr := int4{3, 2, 5, 4}
longerArr := int5{5, 7, 1, 2, 0}
На самом деле так делать не рекомендуется, однако это хороший способ получить представление о том, почему массивы разной длины являются массивами разного типа.
Массив хранится в виде последовательности из n
блоков определенного типа:
Эта память распределяется в момент, когда вы инициализируете переменную типа массив.
В Go нет такой вещи, как передача по ссылке, вместо этого все передается по значению. Если присвоить значение массива другой переменной, то присваиваемое значение просто будет скопировано.
Если вы хотите передать лишь «ссылку» на массив, используйте указатели:
При распределении памяти и в функции массив на самом деле является простым типом данных и работает во многом аналогично структурам.
Срезы можно рассматривать как расширенную реализацию массивов.
Срезы были реализованы в Go, чтобы покрыть некоторые крайне распространенные варианты использования, с которыми разработчики сталкиваются при работе с коллекциями, например, динамическое изменение размера коллекций.
Объявление среза очень похоже на объявление массива, за исключением того, что опускается спецификатор длины:
slice := []int{4, 5, 3}
Если просто смотреть на код, то кажется, что срезы и массивы достаточно похожи, но основное их отличие лежит в реализации и условиях использования.
Срез аллоцируется иначе, чем массив, и по сути является модифицированным указателем. Каждый срез содержит в себе три блока информации:
Из этого следует, что срезы разной длины можно присваивать друг другу. Они имеют один и тот же тип, а указатель, длина и объем могут меняться:
slice1 := []int{6, 1, 2}
slice2 := []int{9, 3}
// slices of any length can be assigned to other slice types
slice1 = slice2
Срез, в отличии от массива, не выделяет память во время инициализации. Фактически, срезы инициализируется с нулевым (nil
) значением.
Когда вы присваиваете срез другой переменной, вы все еще передаете значение. Здесь значение обращается только к указателю, длине и объему, а не к памяти, занимаемой самими элементами.
Чтобы добавить новые элементы к срезу, необходимо использовать функцию append
.
nums := []int{8, 0}
nums = append(nums, 8)
Под капотом это будет выглядеть, как присвоение значения, указанного для нового элемента, и после – возвращение нового среза. Длина нового среза будет на единицу больше.
Если при добавлении элемента длина увеличивается на единицу и тем самым превышает заявленный объем, необходимо предоставить новый объем (в этом случае текущий объем обычно удваивается).
Именно поэтому чаще всего рекомендуется создавать срез с длиной и объемом, указанными заранее (особенно, если вы четко имеете представление какого размера срез вам нужен):
arr := make([]int, 0, 5)
// This creates a slice with length 0 and capacity 5
Массивы и срезы – это совершенно разные вещи, и, следовательно, их варианты использования также разнятся.
Давайте рассмотрим несколько примеров с открытыми исходниками и стандартную библиотеку Go, чтобы понять, что и в каких случаях использовать.
UUID [2] – это 128-битные фрагменты данных, их часто используют для маркировки объекта или сущности. Обычно они представлены в виде шестнадцатеричных значений, разделенных тире:
e39bdaf4-710d-42ea-a29b-58c368b0c53c
В библиотеке Google UUID [3], UUID представлен как массив из 16 байт:
type UUID [16]byte
Это имеет смысл, поскольку мы знаем, что UUID состоит из 128 бит (16 байт). Мы не собираемся добавлять или удалять какие-либо байты из UUID, и поэтому использование массива для его представления будет.
В этом примере мы будем использовать функцию sort.Ints
из sort standard library [4]:
s := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Ints(s)
fmt.Println(s)
// [1 2 3 4 5 6]
Функция sort.Ints
берет срез из целых чисел и сортирует их по возрастанию значений. Срезы здесь использовать предпочтительнее по двум причинам:
Теперь, когда мы рассмотрели ключевые различия между массивами и срезами, а также их варианты использования, я хочу дать несколько советов, чтобы вам было проще решить, какую конструкцию следует использовать:
Как видите, срезы охватывают большинство сценариев для создания приложений на Go. Тем не менее, массивы имеют право на существование, и более того, невероятно полезны, особенно когда появляется подходящий вариант использования.
Автор: Дмитрий
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/328636
Ссылки в тексте:
[1] «Разработчик Golang»: https://otus.pw/GqcK/
[2] UUID: https://www.sohamkamani.com/blog/2016/10/05/uuid1-vs-uuid4/
[3] Google UUID: https://github.com/google/uuid/blob/c2e93f3ae59f2904160ceaab466009f965df46d6/uuid.go#L19
[4] sort standard library: https://golang.org/pkg/sort/#Ints
[5] Источник: https://habr.com/ru/post/465613/?utm_source=habrahabr&utm_medium=rss&utm_campaign=465613
Нажмите здесь для печати.