为什么len()返回一个有符号的值?

dax*_*rod 15 signed go

Go的内置len()函数返回一个签名int.为什么不是uint用来代替?

是否有可能len()返回负面的东西?
据我所知,答案是否定的:

  • 数组:"元素的数量称为长度,永远不会消极."
  • 切片:"任何时候以下关系都成立:0 <= len(s) <= cap(s)"
  • 地图 "地图元素的数量称为其长度".(我在规范中找不到任何明确地将其限制为非负值的内容,但我很难理解地图中的元素少于0个)
  • 字符串 "字符串值是一个(可能是空的)字节序列....字符串s的长度(以字节为单位的大小)可以使用内置函数发现len()"(同样,很难看出序列如何有一个负数字节)
  • 通道 "在通道缓冲区中排队的元素数量(同上)

Vol*_*ker 21

len()(和cap())返回,int因为这是用于索引切片和数组(而不是uint)的内容.所以问题是"当没有负指数时,为什么Go使用有符号整数来索引切片/数组?".

答案很简单:计算索引很常见,如果在无符号整数中完成,这种计算往往容易下溢.有些无辜类似的代码i := a-b+7可能会产生i == 4294967291针对无辜值ab6和10这样的指数可能会溢出你的切片.大量的索引计算发生在0左右,并且使用无符号整数来纠正这些错误并且这些错误隐藏在数学上完全合理和合理的公式之后.这既不安全也不方便.

这是基于经验的权衡:对于使用无符号整数执行的索引计算,通常会发生下溢,而如果使用有符号整数进行索引计算,则溢出更不常见.

另外:在这些情况下使用无符号整数基本上没有任何好处.

  • 这里的例子有错误吗?我不认为 6 - 10 + 7 下溢,是吗?无论如何,我不确定我是否遵循这个论点。在下溢情况下,明显的负索引错误是否比大型无符号整数索引可能导致的更微妙的错误更可取? (3认同)

小智 5

长度和容量

内置函数len和cap接受各种类型的参数并返回int类型的结果.该实现保证结果始终适合int.

Golang是强类型语言,所以如果len()是,uint那么代替:

i := 0 // int
if len(a) == i {
}  
Run Code Online (Sandbox Code Playgroud)

你应该写:

if len(a) == uint(i) {
}
Run Code Online (Sandbox Code Playgroud)

要么:

if int(len(a)) == i {
}
Run Code Online (Sandbox Code Playgroud)

另见:

uint 32位或64位
int无符号整数相同的大小,uint
uintptr 足以存储指针值的未解释位

还用于与C兼容性:CGOC.size_t阵列的在C和大小的类型的int.


Von*_*onC 5

有一个正在进行的提案“问题 31795 Go 2: change lencap如果结果是常量,则返回无类型的 int

可能包含在 Go 1.14(2010 年第一季度)中

我们应该能够做到这一点的len,并cap没有问题-实际上没有任何的STDLIB作为类型检查经修改的型检查显示它

参见CL 179184作为 PoC:这仍然是实验性的。


正如下面peterSO指出的,这已经被关闭了。

罗伯特·格里泽默解释说:

正如您所指出的,使 len 始终无类型的问题在于结果的大小。对于布尔值(以及字符串),大小是已知的,无论是哪种布尔值(或字符串)。

拉斯考克斯 补充说

我不确定这里的成本是否值得。今天有一个简单的规则:len(x)有类型int。更改类型以取决于x将与各种代码更改以非正交方式交互的内容。例如,在提议的语义下,此代码编译:

const x string = "hello"
func f(uintptr)
...
f(len(x))
Run Code Online (Sandbox Code Playgroud)

但是假设然后有人出现并希望能够进行修改x以进行测试或类似的事情,所以他们s/const/var/. 这通常是相当安全的,但现在f(len(x))调用无法进行类型检查,而且它为什么会起作用将是神秘的。

这种变化似乎可能会增加比删除更多的粗糙边缘。

  • [提案:Go 2:如果结果不变,则更改 len、cap 以返回无类型整数](https://github.com/golang/go/issues/31795) 已被撤回并关闭。 (2认同)