Go的内置len()
函数返回一个有符号int
。为什么不使用uint
?
len()
是否有可能返回负面的东西?
据我所知,答案是否定的:
- 数组:"元素的数量称为长度,从不为负。
- 切片:"在任何时候,以下关系都成立:
0 <= len(s) <= cap(s)
地图 - "地图元素的数量称为其长度"。(我在规范中找不到任何明确将其限制为非负值的内容,但我很难理解地图中元素数如何少于 0( 字符串
- "字符串值是一个(可能为空的(字节序列......字符串 s 的长度(以字节为单位的大小(可以使用内置函数
len()
"(同样,很难看出序列如何具有负数字节(
通道 - "在通道缓冲区中排队的元素数(同上(
len()
(和cap()
(返回int
,因为这是用于索引切片和数组(而不是uint
(。所以问题更多的是"为什么 Go 在没有负索引的情况下使用有符号整数来索引切片/数组?
答案很简单:计算索引是很常见的,如果在无符号整数中完成,这种计算往往太容易了。一些无辜的代码(如 i := a-b+7
(可能会为 6 和 10 的 a
和 b
的无辜值生成i == 4294967291
。这样的索引可能会溢出您的切片。许多索引计算发生在 0 左右,并且很难正确使用无符号整数,这些错误隐藏在数学上完全合理和合理的公式后面。这既不安全也不方便。
这是基于经验的权衡:对于使用无符号整数完成的索引计算,下溢往往经常发生,而如果有符号整数用于索引计算,则溢出则不太常见。
另外:在这些情况下,使用无符号整数基本上没有任何好处。
提案正在进行中"问题 31795 Go 2:更改len
,cap
到如果结果是常量,则返回非类型化的 int">
它可能包含在 Go 1.14(2010 年第 1 季度(中
我们应该能够毫无问题地为
len
和cap
做到这一点——事实上也是如此stdlib 中没有任何作为通过修改类型进行类型检查检查器显示
将CL 179184视为PoC:这仍处于实验阶段。
<小时 />正如下面 peterSO 所指出的,这已经关闭。
Robert Griesemer解释说:
正如您所指出的,使 len 始终为非类型化的问题在于结果。对于布尔值(以及字符串(,大小是已知的,无论如何布尔值(或字符串(的种类。
Russ Cox补充说:
我不确定这里的成本是否值得受益。今天有一个简单的规则:
len(x)
具有类型int
。更改类型以取决于x
是什么将以非正交方式与各种代码更改进行交互。例如在建议的语义下,此代码编译:const x string = "hello" func f(uintptr) ... f(len(x))
但是假设有人出现并希望能够修改
x
测试或类似的东西,所以他们s/const/var/
.这通常是公平的安全,但现在f(len(x))
调用无法进行类型检查,它将神秘的为什么它曾经奏效。此更改似乎可能会添加比删除更多的粗糙边缘。
长度和容量
内置函数 len 和 cap 接受各种类型的参数和 返回 int 类型的结果。该实施保证了 结果总是适合整数。
Golang 是强类型语言,所以如果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 中数组的C.size_t
和大小为 int
类型。
从规范:
长度是数组类型的一部分;它必须计算为可由类型为
int
的值表示的非负常量。数组 a 的长度可以使用内置函数len
发现。这些元素可以通过整数索引0
到len(a)-1
寻址。数组类型始终是一维的,但可以组合成多维类型。
我意识到说规范规定 X 可能有点循环,因为规范规定 Y,但由于长度不能超过 int
的最大值,因此len
返回uint
排除值和返回负值一样不可能。