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

Мы начинаем с простых массивов, а затем переходим к Slice, усовершенствованной версии Array. В Slice мы говорим о сопоставлении коллекции пар ключ-значение. Начнем с массивов.

Множество

Как и в любом другом языке программирования, массив в Go представляет собой набор схожих типов данных фиксированного размера.

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

   other language syntax          |            Go syntax
  int[] arr = new int[10]         |           arr := [10]int

Левая часть объявления может показаться знакомой, если вы знакомы с программированием, например C # или Java. Единственное изменение в Go - мы указываем квадратные скобки с максимальным пределом перед типом данных массива.

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

//Declaration 1
var arr = [5]int{1, 2, 3, 4, 5}
//Declaration 2
var arr [5]int
arr = [5]int{1, 2, 3, 4, 5}
//Declaration
arr := [5]int{1,2,3,4,5}

Массивы в Go индексируются с нуля, поэтому мы можем получить доступ к элементам массива, начиная с «0».

var arr [5]int
arr[0] = 1
arr[1] = 2
fmt.Printf(arr[1]) //prints: 2 

Кроме того, массивы в Go ограничены. Если вы попытаетесь получить доступ к элементу за пределами массива, Go выдаст ошибку времени выполнения.

var arr [5]int
arr[0] = 1
arr[1] = 2
fmt.Printf(arr[6])
//Throws below compilation error
invalid array index 6 (out of bounds for 5-element array)

Go также поддерживает многомерные массивы:

//Multi dimensional array
var arrTwoD [2][3]int
for i := 0; i < 2; i++ {
  for j := 0; j < 3; j++ {
   arrTwoD[i][j] = i + j
   }
 }
 fmt.Println("2d: ", arrTwoD) // prints: [[0 1 2] [1 2 3]]

Массивы фиксированной длины всегда жесткие для работы. Выделение памяти для массива происходит один раз при инициализации, что затрудняет увеличение или уменьшение размера массива в зависимости от размера данных. Массивы имеют лучшую скорость и производительность по сравнению со структурой данных, выделенной динамической памятью. Из-за жесткой природы массива в кодовых базах часто можно увидеть, что срезы используются чаще, чем массивы. Давайте посмотрим далее "Ломтики".

Кусочек

Срезы - это усовершенствованные версии массивов, построенных на основе массивов. В отличие от массивов, размер фрагмента может увеличиваться и уменьшаться в зависимости от размера данных. Гибкая природа Slice делает выбор в пользу массива, хотя последний имеет лучшую скорость и производительность по сравнению с первым.

Декларация

  mySlice := []int{1, 2, 3}

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

Динамическое изменение размера

Под капотом компилятор, увидев приведенное выше объявление, создает массив размером 3, добавляет элементы 1,2,3 в массив и указывает переменную mySlice на массив. Нам не нужно иметь дело с базовым массивом самостоятельно. Вместо этого мы работаем только с переменной среза. Это может вызвать вопрос о том, чем срез отличается от массива, если он будет работать с массивом под капотом.

Как уже упоминалось, срез может динамически изменять размер. Давайте посмотрим на встроенный метод append(), чтобы лучше в этом разобраться.

 demoSlice := []int{1,2}
 fmt.Println(demoSlice) // [1,2]
 demoSlice = append(demoSlice,3)
 fmt.Println(demoSlice) // [1,2,3]

Таким образом, мы можем увеличить срез с помощью метода append(). Go управляет базовым массивом, и это позволяет разработчику не беспокоиться о накладных расходах на изменение размера.

Кусочек ломтика

Оператор двоеточия : в Go помогает в создании фрагмента фрагмента.

s1 := demoSlice[0:2] - создает новый массив с элементами с индексом 0 до элемента перед индексом 2. s1 содержит массив [1,2].

s2 := demoSlice[0:] - создает новый массив с элементами с индексом 0 до конца среза. s2 содержит массив [1,2,3].

s3 := demoSlice[:2] - создает новый массив с элементами от начала среза до элемента перед индексом 2. s3 содержит массив [1,2].

Срезы - одна из мощных функций Go, дающая возможность динамически изменять их размер и создавать под-срезы, когда нам нужно работать с меньшими наборами данных.

карта

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

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

Очень важно отметить, что Map - это неупорядоченная коллекция.

Декларация

var m map[--KeyType--]--ValueType--
// Example declaration
var demoMap1 map[int]string
demoMap2 := map[string]bool{}

Назначение и получение с карты

employeeMap := map[int]string{}
//Assignment
employeeMap[1] = "Employee 1"
employeeMap[2] = "Employee 2"
fmt.Println(employee) // map[1:Employee 1 2:Employee 2]
//Retrieving data
name := employeeMap[2]
fmt.Println(employee[1]) //Employee 1
fmt.Println(name) //Employee 2

В отличие от некоторых языков программирования, Go не имеет каких-либо удобных функций для вывода списка ключей или значений карты. Однако он допускает итерацию с использованием оператора range.

for key, value := range employeeMap {
    fmt.Printf("%d is the key for the value %q\n", key, value)
}
Output:
2 is the key for the value "Employee 2"
1 is the key for the value "Employee 1"

Проверка наличия ключа на карте

Проверка наличия пары ключ-значение на карте - одна из очень удобных операций. Доступ к элементу на карте с помощью ключа возвращает два значения - value и bool. Возвращаемое значение bool поможет понять, доступен ли ключ на карте или нет.

name, ok := employeeMap[1]// Employee 1, true
name, ok := employees[1001]// "",false

Удаление

Для удаления значения из карты мы будем использовать встроенный метод delete. Delete примет карту в качестве первого аргумента, а ключ значения, которое необходимо удалить, в качестве второго.

employeeMap := map[int]string{}
//Assignment
employeeMap[1] = "Employee 1"
employeeMap[2] = "Employee 2"
delete(employeeMap, 2)
fmt.Println(employeeMap)
Output:
map[1:Employee 1]

Нет удобной функции для удаления всех элементов с карты.

employeeMap = map[int]string{}
fmt.Println(employeeMap)
Output
map[]

Карты состоят из пар "ключ-значение" и позволяют хранить данные, не полагаясь на индексацию. Это позволяет нам извлекать значения в зависимости от их значения и отношения к другим типам данных.

Заключение

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

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

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

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

Ссылки и дополнительная литература: