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



Go的内置len()函数返回一个有符号int。为什么不使用uint

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

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

cap()(返回int,因为这是用于索引切片和数组(而不是uint(。所以问题更多的是"为什么 Go 在没有负索引的情况下使用有符号整数来索引切片/数组?

答案很简单:计算索引是很常见的,如果在无符号整数中完成,这种计算往往太容易了。一些无辜的代码(如 i := a-b+7(可能会为 6 和 10 的 ab 的无辜值生成i == 4294967291。这样的索引可能会溢出您的切片。许多索引计算发生在 0 左右,并且很难正确使用无符号整数,这些错误隐藏在数学上完全合理和合理的公式后面。这既不安全也不方便。

这是基于经验的权衡:对于使用无符号整数完成的索引计算,下溢往往经常发生,而如果有符号整数用于索引计算,则溢出则不太常见。

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

有一个

提案正在进行中"问题 31795 Go 2:更改lencap到如果结果是常量,则返回非类型化的 int">

它可能包含在 Go 1.14(2010 年第 1 季度(中

我们应该能够毫无问题地为lencap做到这一点——事实上也是如此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 发现。这些元素可以通过整数索引0len(a)-1寻址。数组类型始终是一维的,但可以组合成多维类型。

我意识到说规范规定 X 可能有点循环,因为规范规定 Y,但由于长度不能超过 int 的最大值,因此len返回uint排除值和返回负值一样不可能。

相关内容

  • 没有找到相关文章

最新更新