Почему 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: это все еще эксперимент.