Расскажите об индексировании коллекций в Go

Ответ

Индексирование в Go — это способ доступа к элементам коллекции (массива, среза, строки или карты) по индексу или ключу. Синтаксис — collection[index].

1. Индексация массивов и срезов (Arrays/Slices)

Доступ к элементу осуществляется по его целочисленному индексу, нумерация начинается с 0. Выход за пределы среза или массива вызывает панику.

numbers := []int{10, 20, 30}
fmt.Println(numbers[1]) // Выведет: 20

// numbers[3] // вызовет панику: runtime error: index out of range

2. Индексация карт (Maps)

Доступ к значению осуществляется по ключу. Если ключ не найден, возвращается нулевое значение для типа данных значения. Чтобы отличить отсутствующий ключ от ключа с нулевым значением, используется вторая переменная ok.

ages := map[string]int{"Alice": 25, "Bob": 0}

// Получение значения
fmt.Println(ages["Alice"]) // Выведет: 25

// Проверка наличия ключа
age, ok := ages["Bob"]
fmt.Printf("Bob's age: %d, exists: %tn", age, ok) // Выведет: Bob's age: 0, exists: true

age, ok = ages["Charlie"]
fmt.Printf("Charlie's age: %d, exists: %tn", age, ok) // Выведет: Charlie's age: 0, exists: false

3. Индексация строк (Strings)

Это важный и коварный момент в Go. Строка в Go — это неизменяемая последовательность байт. При индексации строки вы получаете байт по указанному индексу, а не символ (руну).

str := "Привет"

// Неправильный способ доступа к символам в многобайтовой кодировке
fmt.Println(str[0]) // Выведет: 208 (первый байт буквы 'П')
fmt.Println(str[1]) // Выведет: 159 (второй байт буквы 'П')

// Правильный способ — преобразовать строку в срез рун
runes := []rune(str)
fmt.Printf("%cn", runes[0]) // Выведет: П
fmt.Printf("%cn", runes[1]) // Выведет: р

Для безопасной и корректной итерации по символам строки всегда следует использовать цикл for ... range или предварительное преобразование в []rune.