Как работает встроенная функция len() в Go и какова её производительность?

Ответ

В Go len() — это не обычная функция, а встроенная конструкция языка, которая обрабатывается компилятором особым образом. Она возвращает длину для коллекций нескольких типов.

Производительность и сложность: O(1)

Вызов len() всегда выполняется за константное время O(1). Это возможно, потому что длина является неотъемлемой частью внутренней структуры данных и хранится в ней явно. len() просто читает это готовое значение.

  • Слайс (Slice): Структура слайса в памяти (slice header) содержит три поля: указатель на нижележащий массив, длину (len) и ёмкость (cap). len(mySlice) — это прямое чтение поля len.
    // Внутреннее представление слайса
    type sliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
    }
  • Строка (String): Строка, как и слайс, имеет заголовок с указателем на данные и длиной. len(myString) читает это поле. Важно: len() возвращает количество байт, а не рун (символов).
  • Массив (Array): Длина массива является частью его типа и известна на этапе компиляции. len(myArray) — это, по сути, константа.
  • Мапа (Map): Внутренняя структура мапы содержит счётчик количества элементов. len(myMap) возвращает значение этого счётчика.
  • Канал (Channel): len(myChan) возвращает количество элементов, находящихся в данный момент в буфере канала.

Связь с CPU-кэшем

Прямой связи между len() и CPU-кэшем нет. Однако, как и любая операция чтения из памяти, её скорость косвенно зависит от кэша.

Если заголовок слайса или мапы уже находится в L1/L2 кэше процессора (например, из-за того, что вы недавно работали с этой переменной), чтение поля длины будет практически мгновенным. Если данные находятся только в оперативной памяти, доступ займёт больше времени. Но даже в худшем случае это чрезвычайно быстрая операция.