Почему len() возвращает значение со знаком?

Go builtin len() функция возвращает подписанный int. Почему вместо этого использовался uint?

Возможно ли, что len() вернет что-то отрицательное?
Насколько я могу судить, ответ отрицательный:

  • Массивы: "Количество элементов называется длиной и никогда не является отрицательным".
  • Slices: "В любое время выполняется следующее соотношение: 0 <= len(s) <= cap(s)"
  • Карты "Количество элементов карты называется его длиной". (Я не мог найти ничего в спецификации, которая явно ограничивает это неотрицательным значением, но мне трудно понять, как на карте может быть меньше 0 элементов)
  • Строки "Строковое значение - (возможно, пустая) последовательность байтов.... Длина строки s (ее размер в байты) можно открыть с помощью встроенной функции len()" (опять же, трудно понять, как последовательность может иметь отрицательное количество байтов)
  • Channels" количество элементов, помещенных в буфер канала (то же самое)

Ответ 1

len()cap()) возвращает int, потому что это то, что используется для индексации срезов и массивов (не uint). Таким образом, возникает вопрос: "Почему Go использует знаковые целые числа для индексации срезов/массивов, когда нет отрицательных индексов?".

Ответ прост: обычно вычислять индекс, и такие вычисления, как правило, слишком малы, если выполняются в целых числах без знака. Некоторый невинный код, например i := a-b+7, может дать i == 4294967291 для невинных значений для a и b из 6 и 10. Такой индекс, вероятно, переполнит ваш срез. Множество индексов вычислений происходит вокруг 0 ​​и сложно получить правильное использование целых чисел без знака, и эти ошибки скрываются за математически вполне разумными и звуковыми формулами. Это не безопасно и не удобно.

Это компромисс, основанный на опыте: Underflow часто случается для индексных вычислений, выполненных с неподписанными ints, в то время как переполнение намного реже, если для вычисления индекса используются словарные числа.

Дополнительно: в этих случаях в основном используется нулевое преимущество использования целых чисел без знака.

Ответ 2

Длина и емкость

Встроенные функции len и cap принимают аргументы различных типов и возвращает результат типа int. Реализация гарантирует, что результат всегда вписывается в int.

Голанг - это строго типизированный язык, поэтому, если len() был uint, то вместо:

i := 0 // int
if len(a) == i {
}  

вы должны написать:

if len(a) == uint(i) {
}

или

if int(len(a)) == i {
}

Также смотрите:

uint 32 или 64 бит
int того же размера, что и uint
uintptr целое число без знака, достаточно большое для хранения неинтерпретированного бит значения указателя

Также для совместимости с C: CGo C.size_t и размер массива в C имеет тип int.

Ответ 3

От спецификация:

Длина является частью массива; он должен оценивать неотрицательную константу, представляемую значением типа int. Длина массива a может быть обнаружена с помощью встроенной функции len. Элементы могут быть адресованы целыми индексами 0 через len(a)-1. Типы массивов всегда одномерные, но могут быть составлены для формирования многомерных типов.

Я понимаю, что, может быть, небольшой циркуляр, чтобы сказать, что спецификация диктует X, потому что спецификация диктует Y, но поскольку длина не может превышать максимальное значение int, она одинаково невозможна для len для возврата uint -exclusive значение, чтобы вернуть отрицательное значение.

Ответ 4

Выполняется предложение "выпуск 31795 Go 2: измените len, cap, чтобы он возвращал нетипизированный тип int, если результат постоянен"

Это может быть включено для Go 1.14 (1 квартал 2010 г.)

мы должны быть в состоянии сделать это для len и cap без проблем - и действительно, в stdlib их нет, так как проверка типов через модифицированную проверку типов показывает

Смотрите CL 179184 как PoC: это все еще эксперимент.