Введение
В Go массивы и slices являются структурами данных, которые состоят из иерархической последовательности элементов. Эти собрания данных отлично подходят для работы с множеством связанных значений. Они позволяют вам сохранять вместе данные, которые вместе appertain, упрощать ваш код и выполнять те же методы и операции с множеством значений одновременно.
尽管在 Go 中数组和切片都是有序元素序列,但两者之间存在显著差异。在 Go 中的 массив — это структура данных, состоящая из иерархической последовательности элементов, для которой определенна ее вместимость при создании.一旦 массив выделил свой размер, размер больше не может быть изменен. С другой стороны, slice является переменной длины версией массива, обеспечивая больше гибкости для разработчиков, использующих эти структуры данных. Сlices составляют то, что вы можете посчитать как массивы в других языках.
учитывая эти различия, есть конкретные ситуации, когда вы используете одну из них. Если вы новичок в Go, определить, когда их использовать, может быть запутанно: хотя гибкость slices делает их более подходящим выбором в большинстве ситуаций, есть конкретные ситуации, в которых массивы могут оптимизировать производительность вашего программного обеспечения.
Этот статья рассказывает о массивах и слайсах в деталях, которые позволяют вам получить необходимые знания для выбора между этими типами данных. При этом вы также переглянуты наиболее часто использующиеся способы объявления и работы с обами абстракционными datatypes. Статья будет начаться с описанием массивов и как manipulровать ими, после чего последует объяснение слайсов и как они отличаются. ТуторIAL первым предоставляет описание массивов и как работать с ними, затем последует объяснение слайсов и как они отличаются.
Массивы
Арrays – это собрание datastructures с фиксированным числом элементов. Поскольку размер арray привязался к одному значению, datastructure только должен выделить память один раз, в отличие от datastructure с изменяемым размером, которой datastructure должно динамически выделить память, чтобы он мог становиться более или менее в будущем.尽管数组的固定长度使其在处理数据时略显僵化,但一次内存分配可以提高程序的速度和性能。因此,开发人员通常使用数组来优化程序,特别是在数据结构永远不会需要可变数量元素的情况下。
Определение массива
Массивы в Go представляются декларацией размеров в круглых括号 [ ]
, после которой указывается тип данных элементов. Массив в Go должен иметь все его элеMENTЫ одного и того же типа данных. После типа данных можно объявить значения отдельных элементов в круглых括号 { }
.
Следующий пример показывает общее правило для декларации массива:
Примечание: ИмPORTANT также помните, что каждая декларация нового массива создает свой собственный тип. Так, хотя [2]int
и [3]int
оба имеют элементы整数, их различные длины делают их типы несовместимыми.
Если вы не декларировали значения элементов массива, то по умолчанию они равны нулевым значению, которым для整数 является 0
, а для строк – пустая строка.
Например, следующий массив numbers
имеет три整数 элемента, которые ещё не имеют значений:
Если вы выведите numbers
, вы получите следующий вывод:
Output[0 0 0]
Если вы хотели бы записать значения элементов при создании массива, поместите значения в круглых括号. Массив строк с установленными значениями выглядит так:
Вы можете хранить массив в переменной и выводить его:
Исполнение программы с предыдущими строками даст вам следующий вывод:
Output[blue coral staghorn coral pillar coral elkhorn coral]
Обратите внимание, что между элементами массива в момент печати нет никакого различия, что делает трудно определить, где один элемент заканчивается и начинается другой. В связи с этим иногда удобно использовать функцию fmt.Printf
, которая может отформатировать строку перед ее печатью на экран. Используйте следующий код:
Это приведет к следующему результату:
Output["blue coral" "staghorn coral" "pillar coral" "elkhorn coral"]
Теперь каждое значение окружено кавычками. Существенно, что \n
заставляет форматировщик добавить новую строку в конце.
С определенной идеей о том, как объявляются массивы и о том, что они содержат, вы можете перейти к изучению того, как указать элементы массива с помощью номера индекса.
Индексация массивов (и слов)
Каждый элемент массива (как и слова) может быть вызван индивидуально с помощью индексации. Каждый элемент соответствует номеру индекса, который является числом int
, начинающимся с нуля (0
) и увеличивающимся.
В следующих примерах мы будем использовать массив, но вы также могли бы использовать слайс, так как у них одинаковое поведение при индексации.
Для массива coral
распределение индексов выглядит следующим образом:
“blue coral” | “staghorn coral” | “pillar coral” | “elkhorn coral” |
---|---|---|---|
0 | 1 | 2 | 3 |
Первый элемент, строка "blue coral"
, начинается с индекса 0
и разрывается при индексе 3
с элементом "elkhorn coral"
.
Поскольку каждый элемент в последовательности или массиве имеет соответствующий индекс, мы можем доступиться и изменить их так же, как это делается с другими последовательными типами данных.
Теперь мы можем вызвать отдельный элемент последовательности или массива, используя его индекс:
Outputstaghorn coral
Индексы для этого последовательности рассчитываются от 0
до 3
, как показано в предыдущей таблице. Таким образом, чтобы вызвать любой элемент индивидуально, мы будем использовать их индексы так:
Если мы вызываем массив coral
с любым индексом, который больше чем 3
, то это будет недопустимо, так как ни один элемент не будет ваalid:
Outputpanic: runtime error: index out of range
Когда индексировать массив или последовательность, вы должен всегда использовать положительное число. При использовании отрицательного числа, как в некоторых языках, это приведет к ошибке:
Outputinvalid array index -1 (index must be non-negative)
Мы могли бы конcatenтировать значение элемента внутри массива или последовательности с другими строками, используя оператор +
:
OutputSammy loves blue coral
Мы получили конcatenацию первого элемента с строкой "Sammy loves "
.
С помощью индексов, которые соответствуют элементам в массиве или последовательности, мы можем доступиться к каждому элементу discretely и работать с этими элементами. Далее мы будем рассмотреть как изменять элемент на определенном индексе.
Изменение элементов
Мы можем использовать индексирование, чтобы изменять элементы внутри массива или слайса, устанавливая индексный элемент с заданным номером равным другому значению. Это дает нам большее управление данными в наших слайсах и массивах и позволит нам программно манипулировать отдельными элементами.
Если мы хотим изменить строковое значение элемента с индексом 1
массива coral
с "staghorn coral"
на "foliose coral"
, мы можем сделать это так:
Теперь, когда мы печатаем coral
, массив будет different:
Output["blue coral" "foliose coral" "pillar coral" "elkhorn coral"]
Теперь, когда вы умеют манипулировать отдельными элементами массива или слайса, посмотрим на пару функций, которые предоставит вам больше гибкости при работе с коллекционными данными типов.
Обращение элементов с помощью len()
В Go, len()
является встроенной функцией, предназначенной для работы с массивами и слайсами. Как и с строками, вы можете вычислить длину массива или слайса, используя len()
и передавая массив или слайс в качестве параметра.
Например, чтобы найти, сколько элементов содержится в массиве coral
, вы будете использовать:
Если вы напечатаете длину массива coral
, вы получите следующий результат:
Output4
Это даст длину массива 4
в data type int
, что correct, because the array coral
has four items:
Если вы создаете массив целых с большим количеством элементов, вы также можете использовать функцию len()
:
Это приведет к следующему результату:
Output13
хотя эти примеры массивов содержат относительно небольшое количество элементов, функция len()
особенно useful, when you determine, how many elements are in very large arrays.
Next, we will cover how to add an element to a collection data type, and demonstrate how, because of the fixed length of arrays, appending these static data types will result in an error.
Appending Elements with append()
append()
is a built-in method in Go that adds elements to a collection data type. However, this method will not work when used with an array. As mentioned before, the primary way in which arrays are different from slices is that the size of an array cannot be modified. This means that while you can change the values of elements in an array, you can’t make the array larger or smaller after it has been defined.
Let’s consider your coral
array:
Пусть вы хотите добавить элемент "black coral"
к этому массиву. Если вы попробуете использовать функцию append()
для массива, введя:
Вы получите ошибку, так как ваш выход:
Outputfirst argument to append must be slice; have [4]string
. Чтобы исправить это, давайте знакомиться более детально с типом данных подстроки, как его definir и как конвертировать из массива в подстроку.
Слои
А слой – это тип данных в Go, который является модифицируемым, или изменяемым, последовательным элементов. Поскольку размер слоя может быть переменным, имеется больше свободы при работе с данными; когда работать с собраниями данных, которые могут расширяться или уменьшаться в будущем, использование типа данных слой гарантирует, что ваш код не получит ошибок при пытке изменять длину собрания. При работе с многоэлементными собраниями или при итерации над элементами, когда вы желаете легко изменять эти элементы, вы很可能 want to work with the slice data type. When you need to store a lot of elements or iterate over elements and you want to be able to readily modify those elements, you’ll likely want to work with the slice data type.
Определение слоя
Плитки определяются объявлением типа данных, который пред precedes by an empty pair of square brackets ([]
), and a list of elements between curly brackets ({}
). Вы можете заметить, что в отличие от массивов, которые требуют значения int
между круглыми скобками для указания конкретной длины, сечасть имеет ничего между круглыми скобками, представляя его переменную длину.
Допустим, мы создаем сечью, которая содержит элементы типа строки:
Когда вы печатаете этот сечь, вы можете видеть элементы, которые присутствуют в сечении:
Это будет выдать следующий результат:
Output["shark" "cuttlefish" "squid" "mantis shrimp" "anemone"]
Если вы хотели бы создать сечь определенной длины без пополнения элементов коллекции, вы можете использовать встроенную функцию make()
:
Если вы выведите этот сечь, вы получите:
Output["" "" ""]
Если вы хотели бы предоставить память для определенной капиците, вы можете передать третью аргументом в make()
:
Это будет создать сечь с длиной 3
и предоалложенной капиците 5
элементов.
Теперь вы знаете как декларировать сечь. Однако это еще не решит проблему с ошибкой, которой была присутсвуйте ранее с coral
. Чтобы использовать функцию append()
с coral
, вы первым делом должны научиться разбивать части аray.
Сlicing Arrays Into Slices
Использование индексных чисел для определения начальных и конечных точек позволяет вызвать подсекцию значений внутри массива. Это называется слойкой массива, и вы можете это сделать, создав последовательность индексов, разделенных двоеточием, в форме [первый_индекс:второй_индекс]
. Однако необходимо заметить, что при слойке массива полученный результат является слоем, а не массивом.
Предположим, что вы хотите просто напечатать средние элементы массива coral
, не включая первый и последний элемент. Это можно сделать, создав слой, начиная с индекса 1
и заканчивая just before индекса 3
:
Выполнение программы с этим запросом даст следующий результат:
Output[foliose coral pillar coral]
При создании слоя, как в [1:3]
, первое число означает, с какого элемента начать слой (включительно), а второе число — это сумма первого числа и количества элементов, которые вы хотите извлечь:
array[starting_index : (starting_index + length_of_slice)]
В этом конкретном случае вы вызвали второй элемент (или индекс 1) в качестве точки начала и вызвало два элемента в общем:
array[1 : (1 + 2)]
Как это выглядит:
Если вы хотите установить начало или конец массива в качестве точки начала или конца слоя, вы можете опустить одно из чисел в синтаксисе array[первый_индекс:второй_индекс]
. Например, если вы хотите напечатать первые три элемента массива coral
— которыми будут "blue coral"
, "foliose coral"
, и "pillar coral"
— вы можете сделать это, напечатав:
Это напечатает:
Output[blue coral foliose coral pillar coral]
Это вывело начало массива, прервавшись на индекс 3
.
Чтобы включить все элементы в конце массива, вы можете использовать синtax переопределения:
Это даст следующий отсек:
Output[foliose coral pillar coral elkhorn coral]
Эта секция рассказывала о том, как вызвать отдельные части аппарата путем извлечения подсекций. Следующим вам потребуется узнать, как использовать присваивание, чтобы преобразовать весь массив в отсек.
Конвертация массива в отсек
Если вы создаете массив и решите, что его длина должна быть разной, вы можете его преобразовать в отсек. Чтобы преобразовать массив в отсек, используйте процесс извлечения, который вы leaned во времени этого шага, но этот раз, выберите все значения, опуская обе индексы, которые будут определять концы:
Измените значение coral
так, чтобы получить новый массив, который будет содержать все значения первого массива:
Если вы выведите coralSlice
, вы получите следующий вывод:
Output[blue coral foliose coral pillar coral elkhorn coral]
Теперь попробуйте добавить элемент black coral
как в случае массива, используя append()
с новом преобразованным отсеком:
Это будет вывести отсек с добавленным элементом:
Output["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral"]
Мы также можем добавить более одного элемента в один присвоенный значение append()
.
Output["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral" "antipathes" "leptopsammia"]
Добавить два объекта в одну последовательность можно использовать append()
, но вы должны расширить второй аргумент для добавления используя синtax ...
расширения:
Output["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral" "antipathes" "leptopsammia" "massive coral" "soft coral"]
Теперь, когда вы узнали как добавлять элементы к вашей последовательности, мы поглядем как это делается с удалением одного.
Удаление элемента из последовательности
Как и в других языках, Go не предоставляет ни одной функции, которая бы позволила удалить элемент из последовательности. Элементы должны быть удалены из последовательности путем изменения их индекса.
Чтобы удалить элемент, вы должены измерить первый и последний индекс элементов, которые должны быть удалены, а затем присоединить эти два новых кусков вместе без удаленного элемента.
Если i
– это индекс элемента, который хотят удалить, то формат этого процесса будет иметь вид следующий:
Из коралЛис
, удалите элемент "elkhorn coral"
. Этот элемент находится на позиции 3
.
Output["blue coral" "foliose coral" "pillar coral" "black coral" "antipathes" "leptopsammia" "massive coral" "soft coral"]
Теперь элемент на позицию 3
, строка "elkhorn coral"
, более не включен в нашу последовательность коралЛис
.
Мы также можем удалить диапазон с помощью такой же методики. Примерно так: мы хотели бы удалить не только элемент "elkhorn coral"
, но и "black coral"
и "antipathes"
. Можно использовать диапазон в выражении для этого:
Это приведет к удалению индексов 3
, 4
, и 5
из кучи:
Output["blue coral" "foliose coral" "pillar coral" "leptopsammia" "massive coral" "soft coral"]
Теперь, когда вы знаizте как добавлять и удалять элементы из кучи, давайте рассмотрим как измерить размер данных, который может содержаться в любой определенной времени.
ИзмерятьCapacidad Сlices с помощью cap()
Поскольку кучи имеют переменную длину, метод len()
не является лучшим вариантом, чтобы получить размер этого типа данных. Вместо этого вы можете использовать функцию cap()
, которая показывает, как много элементов может содержать куча, это определяется тем, как много памяти уже был allоцирован для кучи.
Примечание: Поскольку длина и капацитет аллоцированной области всегда равны, функция cap()
не будет работать на аллоцированных массивах.
Обычно используют cap()
для создания кучи с пресетом числа элементов и заполнения этих элементов программно. Это предотвигает возможность неоправданых аллоцирований, которые могли бы произойти при использовании append()
для добавления элементов после капацитета, который уже был allоцирован.
Пусть применим этот случай к составлению списка чисел от 0
до 3
. Мы можем использовать append()
в цикле для этого, или первоначально предоставлять размер сегмента и использовать cap()
для цикла, чтобы заполнить значения.
Первым образом, мы можем рассмотреть использование append()
:
Output[0 1 2 3]
В этом примере мы создали сегмент, а потом создали цикл, который будет перебираться четыре раза. Каждый раз он добавлял текущее значение циклового переменного i
в индекс сегмента numbers
. Однако, это может привести к неоправданым вы allocationм памяти, которые могу замедлить работу вашего программы. При добавлении к пустому сегменту, каждый раз при поиске добавления элементов программа проверяет его объем. Если добавившийся элемент превысит этот объем, програма будет выделять дополнительную память, что может привести к дополнительной нагрузке в вашу программу.
Теперь мы распечатаем сегмент без использования append()
путем предоставления определенной длины/сapаcity:
Output[0 1 2 3]
В этой примере мы использовали make()
для создания сегмента и имели его предоставлять 4
элементов. Затем мы использовали функцию cap()
в цикле для перебирать все начатокие значения, заполняя каждое до тех пор, пока не достигнут предоставленной capacitty. В каждом цикле мы помещаем текущее значение циклового переменного i
в индекс сегмента numbers
.
При использовании функций append()
и cap()
получается тот же самый результат, но пример с cap()
избегает дополнительных выallocваний памяти, которые бы были необходимы при использовании функции append()
.
Создание многоуровневых объектов
Вы также можете определять разрезы, которые состоят из других разрезов, каждый внутри более крупных разрезов. Такие как эти, называются многоуровневыми разрезами. Это можно представить как представление многоуровневых координат; например, коллекция из пяти разрезов, каждый из которых имеет длину семи элементов, может представлять двухмерную градуированную таблицу с длиной стола пять и высокой шесть.
Посмотрите на следующий пример многоуровневого разреза:
Чтобы получить значение любого элемента в этой разрезе, мы будем использовать несколько индексов, один для каждой dimенсии конструкта:
В предыдущем коде мы первым указываем элемент на индексe 0
разреза на индексe 1
, а затем указываем элемент на индексe 0
разреза на индексe 0
. Это даст следующий результат:
OutputSammy
shark
Далее приведены значения индексов для всех остальных элементов:
При работе с мультидименсиональными изолицами важно иметь в виду, что для доступности определенных элементов в соответствующих вложенных изолицах вы будете использовать более одного индекса.
Конслэйн
В этой уроке вы узнали основы работы с массивами и изолицами в Go. Вы прошли через несколько практических примеров, которые помогли выявить как различия между тем, что массивы фиксированы в длину, а изолицы могут изменяться в размер, и как это отразилось на ситуационном использовании этих datastructures.
Для дальнейшего изучения datastructures в Go обратите свое внимание к статьи «Изучаем Мары в Go», или изучите весь серию «Как Код в Go».
Source:
https://www.digitalocean.com/community/tutorials/understanding-arrays-and-slices-in-go