Расскажите об индексировании коллекций в 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.

Ответ 18+ 🔞

А, индексирование в Go, говоришь? Ну это ж классика, блядь! Сидишь такой, думаешь — ну что тут может быть сложного, collection[index] и всё дела. Ан нет, ёпта, тут такие подводные камни, что мама не горюй!

Вот смотри, с массивами и срезами вроде всё просто — как в нормальных языках. Нумерация с нуля, хуле тут.

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

Но попробуй вылезти за пределы — получишь пизды от рантайма: index out of range, и привет, программа накрылась медным тазом. Так что смотри в оба, блядь!

А вот с картами уже интереснее, ёбана! Ты думаешь — взял ключ, получил значение? Ага, щас! Если ключа нет — тебе вернётся нулевое значение типа. И как отличить, что ключа нет, от ситуации, где там реально ноль лежит? А вот так:

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

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

Видишь? Вторая переменная ok тебе говорит — есть ключ или нет. Без этого — нихуя не понятно, честно говоря!

Но самое, блядь, интересное — это строки! Вот тут-то и начинается цирк, ёпта! Строка в Go — это последовательность байтов, а не символов. И когда ты пишешь str[0] для строки "Привет" — ты получаешь не букву "П", а первый байт этой буквы в UTF-8!

str := "Привет"
fmt.Println(str[0]) // Выведет: 208 (первый байт буквы 'П')
fmt.Println(str[1]) // Выведет: 159 (второй байт буквы 'П')

Вот это пиздец, да? Ты думал символ получишь, а тебе какая-то хуйня в виде числа прилетает! И так для каждой русской буквы, блядь, потому что они многобайтовые!

Правильный способ — либо в срез рун преобразовать:

runes := []rune(str)
fmt.Printf("%cn", runes[0]) // Выведет: П

Либо через for ... range итерироваться, он за тебя всё разберёт. А если будешь по-простому индексировать — получишь ебанину полную, в рот меня чих-пых!

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