> Как посчитать количество элементов в массиве (Go)

Уровень: senior · Роль: backend · Категория: Технические вопросы

Компании: QualityExpert

Стек: Go

> Пример ответа

Короткий ответ

В Go количество элементов в массиве (или срезе) получают через встроенную функцию len(). Для массива фиксированной длины это константа времени компиляции, для среза - O(1) операция, так как длина хранится в структуре заголовка среза. len() работает для строк, map, каналов и указателей на массивы. Важно не путать len() с cap() - ёмкостью, которая показывает зарезервированное место под срез.

Подробное объяснение

В Go массивы имеют фиксированную длину, заданную при объявлении. Функция len() возвращает количество элементов для любого типа, поддерживающего понятие длины:

  • Массив - длина известна на этапе компиляции, len() заменяется константой.
  • Срез (slice) - длина хранится в runtime-заголовке slice (структура из указателя, длины и ёмкости), поэтому len() - это чтение поля, O(1).
  • Строка - возвращает количество байт, не символов (для Unicode нужно использовать utf8.RuneCountInString).
  • Map - возвращает количество пар ключ-значение.
  • Канал - возвращает количество элементов, ожидающих чтения в буфере (не для unbuffered каналов).

Для массива len() можно использовать в выражениях, требующих констант, например, при объявлении другого массива: var b [len(a)]int.

На практике

В реальном коде len() используется повсеместно:

  • Итерация по срезу: for i := 0; i < len(s); i++.
  • Проверка пустоты: if len(s) == 0 (предпочтительнее, чем s == nil, так как nil-срез и пустой срез ведут себя одинаково).
  • Копирование: copy(dst, src) автоматически ограничивается минимальной длиной.
  • Работа с JSON, сериализация, batch-обработка - везде, где нужно знать количество элементов.

Для многомерных массивов len() применяется к каждому измерению отдельно: len(matrix) - число строк, len(matrix[0]) - число столбцов.

Пример кода

GO
package main
import "fmt"
func main() {
// Массив фиксированной длины
arr := [5]int{1, 2, 3, 4, 5}
fmt.Println(len(arr)) // 5
// Срез
slice := []string{"a", "b", "c"}
fmt.Println(len(slice)) // 3
// Срез из массива
part := arr[1:3]
fmt.Println(len(part)) // 2
// Строка - возвращает байты
str := "привет"
fmt.Println(len(str)) // 12 (6 символов * 2 байта)
// Map
m := map[string]int{"x": 1, "y": 2}
fmt.Println(len(m)) // 2
// nil-срез
var nilSlice []int
fmt.Println(len(nilSlice)) // 0
}

Как отвечать на собеседовании

Начните с прямого ответа: len(). Затем уточните, что для срезов это O(1), потому что длина хранится в заголовке. Упомяните разницу между len() и cap(). Покажите понимание edge cases: nil-срез, пустой срез, строки в байтах. Если спросят про производительность - скажите, что для массива компилятор подставляет константу, для среза это просто чтение поля. Хорошо добавить пример с многомерным массивом или срезом из массива, чтобы показать глубину понимания.

Что проверяет интервьюер

Интервьюер оценивает:

  • Базовое знание синтаксиса Go.
  • Понимание внутреннего устройства среза (структура из указателя, длины, ёмкости).
  • Осознание разницы между массивом и срезом.
  • Знание нюансов: len() для строк возвращает байты, а не руны.
  • Умение говорить о сложности операций.

Типичные ошибки

  • Путают len() и cap() - для среза это разные понятия.
  • Считают, что len() для строки возвращает количество символов - на самом деле байт.
  • Используют s == nil для проверки пустоты среза вместо len(s) == 0.
  • Забывают, что len() для канала возвращает только буферизованные элементы, а не общее количество отправленных.
  • Пытаются применить len() к указателю на массив без разыменования - для *[5]int нужно писать len(*p), хотя Go позволяет len(p) для указателя на массив (автоматическое разыменование).

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью