После изучения данного урока вы сможете:
- Объявлять и инициализировать массивы;
- Присваивать и получать доступ к элементам массива;
- Итерировать элементы массива.
Массивом называют упорядоченный набор элементов фиксированной длины. В данном уроке массивы будут использоваться для хранения названий планет и карликовых планет нашей солнечной системы, но вы можете использоваться любые данные по собственному желанию.
Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎
Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.
Содержание статьи
- Объявление массива и получение доступа к его элементам
- Диапазон значений массива в Golang
- Инициализация массивов через композитные литералы в Go
- Итерация через массивы в Go
- Копирование массивов в Golang
- Массивы из массивов в Golang
Быть может, вы что-то коллекционируете? Или собирали что-то в детстве? Марки, монеты, наклейки, книги, туфли, медали, диски или что-то еще?
Массивы также предназначены для сбора элементов одного типа. Подумайте, какую коллекцию вы смогли бы представить в виде массива?
Объявление массива и получение доступа к его элементам
Следующий массив planets
содержит ровно восемь элементов:
1 |
var planets [8]string |
У каждого элемента массива одинаковый тип. В данном случае planets
является массивом строк.
К элементу массива можно получить доступ через использование квадратных скобок []
с нужным индексом, отсчет начинается с 0. Внизу представлен пример программы, а также проиллюстрирована схема.
1 2 3 4 5 6 7 8 |
var planets [8]string planets[0] = "Меркурий" // Присваивает планете индекс 0 planets[1] = "Венера" planets[2] = "Земля" earth := planets[2] // Получает планету с индексом 2 fmt.Println(earth) // Выводит: Земля |
Планеты с индексами от 0 до 7
Хотя только трем планетам были присвоены индексы, всего в массиве planets
находится восемь элементов. Длину массива можно определить через встроенную функцию len
. Другие элементы с нулевым значением своего типа, то есть пустая строка:
1 2 |
fmt.Println(len(planets)) // Выводит: 8 fmt.Println(planets[3] == "") // Выводит: true |
На заметку: В Go есть полезные встроенные функции, использовать которые можно без оператора
import
. Функцияlen
определяет длину типов. В данном случае возвращается размер массива.
Вопросы для проверки:
- Как можно получить доступ к первому элементу массива
planets
? - Каким будет значение элементов нового массива целых чисел по умолчанию?
Диапазон значений массива в Golang
У массива из восьми элементов индексы от 0 до 7. При попытке получить доступ к элементу за пределами диапазона массива компилятор Go сообщит об ошибке:
1 2 3 4 5 6 |
var planets [8]string // 8 - неверный номер индекса // находится за пределами диапазона массива из 8 элементов planets[8] = "Плутон" pluto := planets[8] |
Если компилятор Go не в состоянии зафиксировать ошибку, во время запуска программы может произойти сбой:
1 2 3 4 5 |
var planets [8]string i := 8 planets[i] = "Плутон" // Сбой: ошибка запуска pluto := planets[i] // индекс выходит за пределы диапазона |
Сбой приведет к аварийному завершению программы, что все-таки лучше, нежели модификация памяти, что не относится к массиву planets
. Будь это язык программирования вроде С, все могло бы закончиться неопределенным поведением.
Вопрос для проверки:
Приведет ли planets[11]
к ошибке во время компиляции или к сбою во время запуска?
Инициализация массивов через композитные литералы в Go
Композитный литерал является кратким синтаксисом для инициализации любого композитного типа с нужными значениями. Вместо объявления массива и присваивания каждого элемента по-очереди, композитный литеральный синтаксис Go объявит и инициализирует массив за один шаг, как показано в следующем примере:
1 |
dwarfs := [5]string{"Церера", "Плутон", "Хаумеа", "Макемаке", "Эрида"} |
Внутри фигурных скобок {}
находятся пять строк, что разделяются запятыми и являются элементами нового массива.
При работе с крупными массивами разделение композитного литерала на множество строк может сделать код более понятным. Компилятор Go может подсчитать количество элементов внутри композитного литерала, для этого вместо числа ставится многоточие (...
) . У массива planets
в следующем примере по-прежнему фиксированная длина:
1 2 3 4 5 6 7 8 9 10 |
planets := [...]string{ // Компилятор Go подсчитывает элементы "Меркурий", "Венера", "Земля", "Марс", "Юпитер", "Сатурн", "Уран", "Нептун", // Запятая в самом конце является обязательной } |
Задание для проверки:
Сколько планет указано в Листинге 3? Используйте встроенную функцию len
, чтобы выяснить.
Итерация через массивы в Go
Итерация через каждый элемент массива напоминает итерацию каждого символа строки. Мы ранее говорили об этом в уроке о строках в Golang. Это показано в примере ниже:
1 2 3 4 5 6 |
dwarfs := [5]string{"Церера", "Плутон", "Хаумеа", "Макемаке", "Эрида"} for i := 0; i < len(dwarfs); i++ { dwarf := dwarfs[i] fmt.Println(i, dwarf) } |
Ключевое слово range
возвращает индекс и значение каждого элемента массива посредством использования меньшего количества кода и меньшей вероятностью совершения ошибок, что показано в коде ниже:
1 2 3 4 5 |
dwarfs := [5]string{"Церера", "Плутон", "Хаумеа", "Макемаке", "Эрида"} for i, dwarf := range dwarfs { fmt.Println(i, dwarf) } |
Результат будет одинаковым для обеих программ:
1 2 3 4 5 |
0 Церера 1 Плутон 2 Хаумеа 3 Макемаке 4 Эрида |
На заметку: Помните, что вы можете использовать пустой идентификатор (подчеркивание), если вам не нужен индекс переменной, предоставленный range
.
Вопросы для проверки:
- Каких ошибок можно избежать, используя ключевое слово
range
для итерации через массив? - Когда вместо
range
лучше использовать цикл for?
Копирование массивов в Golang
Присваивание массива новой переменной или передача его функции приводит к копированию всего его содержимого, что показано в следующем примере:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
planets := [...]string{ "Меркурий", "Венера", "Земля", "Марс", "Юпитер", "Сатурн", "Уран", "Нептун", } planetsMarkII := planets // Копирует массив planets planets[2] = "упс" // Прокладывает путь для межзвездного шунтирования fmt.Println(planets) // Выводит: [Меркурий Венера упс Марс Юпитер Сатурн Уран Нептун] fmt.Println(planetsMarkII) // Выводит: [Меркурий Венера Земля Марс Юпитер Сатурн Уран Нептун] |
У массивов есть значения, функции также передают значения, а это значит, что функция terraform
в следующем листинге совершенно неэффективна:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package main import "fmt" // terraform ни к чему не приводит func terraform(planets [8]string) { for i := range planets { planets[i] = "New " + planets[i] } } func main() { planets := [...]string{ "Меркурий", "Венера", "Земля", "Марс", "Юпитер", "Сатурн", "Уран", "Нептун", } terraform(planets) fmt.Println(planets) // Выводит: [Меркурий Венера Земля Марс Юпитер Сатурн Уран Нептун] } |
Функция terraform
оперирует с копией массива planets
, поэтому модификации не затронут planets
в функции main
.
Также важно понимать, что длина массива является частью его типа. Типы [8]string
и [5]string
оба представляют собой наборы строк, но это совершенно разные типы. При попытке передать массив с другой длиной компилятор Go сообщит об ошибке:
1 2 |
dwarfs := [5]string{"Церера", "Плутон", "Хаумеа", "Макемаке", "Эрида"} terraform(dwarfs) // Нельзя использовать dwarfs (типа [5]string) как тип [8]string в качестве аргумента terraform |
Именно по этой причине массивы редко используются как параметры функции, в отличие от срезов массива, о которых мы поговорим в следующем уроке.
Задания для проверки:
- Как Земле удалось выжить в
planetsMarkII
из Листинга 6? - Как можно модифицировать Листинг 7, чтобы массив
planets
изmain
изменился?
Массивы из массивов в Golang
Пока что мы разобрали только массивы строк. В Go также можно создавать массивы целых чисел, чисел с плавающей запятой и даже массивы из массивов. Шахматная доска 8 х 8 представлена в следующем примере как массив из массива строк:
1 2 3 4 5 6 7 8 9 10 |
var board [8][8]string // Массив из восьми массивов с восемью строками board[0][0] = "r" board[0][7] = "r" // Ставит ладью на клетку с координатами [ряд][столбец] for column := range board[1] { board[1][column] = "p" } fmt.Print(board) |
Задание для проверки:
Подумайте об игре Судоку. Как можно объявить сетку целых чисел размером 9 х 9?
Заключение
- Массив является упорядоченным набором элементов с фиксированной длиной;
- Композитные литералы помогают легко инициализировать массивы;
- Ключевое слово
range
может итерировать через массивы; - При получении доступа к элементам массива нужно придерживаться границ диапазона;
- Во время присваивания и передачи функций массивы копируются.
Итоговое задание для проверки:
- Допишите Листинг 8 для отображения всех шахматных фигур на их стартовых позициях, используя символы kqrbnp для черных фигур в верхней части доски, а также символы в верхнем регистре KQRBNP для белых фигур в нижней части доски;
- Напишите функцию для отображения доски;
- Вместо строк, используйте
[8][8]rune
для доски. Помните, что литералы rune должны быть окружены одинарными кавычками и могут выводиться на экран через специальный символ%c
.
Администрирую данный сайт с целью распространения как можно большего объема обучающего материала для языка программирования Go. В IT с 2008 года, с тех пор изучаю и применяю интересующие меня технологии. Проявляю огромный интерес к машинному обучению и анализу данных.
E-mail: vasile.buldumac@ati.utm.md
Образование
Технический Университет Молдовы (utm.md), Факультет Вычислительной Техники, Информатики и Микроэлектроники
- 2014 — 2018 Universitatea Tehnică a Moldovei, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Universitatea Tehnică a Moldovei, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»