【发布时间】:2023-03-02 21:52:02
【问题描述】:
Go 的内置 len() function 返回一个签名的 int。为什么不使用 uint 代替?
len() 是否有可能返回负面信息?
据我所知,答案是否定的:
【问题讨论】:
-
如果您想处理切片的第 2147483648 个元素,
uint可能会更好。但是,如果你想处理第 4294967296 个元素,你就会遇到麻烦。
Go 的内置 len() function 返回一个签名的 int。为什么不使用 uint 代替?
len() 是否有可能返回负面信息?
据我所知,答案是否定的:
【问题讨论】:
uint 可能会更好。但是,如果你想处理第 4294967296 个元素,你就会遇到麻烦。
内置函数 len 和 cap 接受各种类型的参数和 返回 int 类型的结果。该实施保证了 结果总是适合 int。
Golang 是强类型语言,所以如果 len() 是 uint 则不是:
i := 0 // int
if len(a) == i {
}
你应该写:
if len(a) == uint(i) {
}
或:
if int(len(a)) == i {
}
另见:
uint32 位或 64 位int与uint大小相同uintptran unsigned integer large enough to store the uninterpreted bits of a pointer value
也为了与 C 兼容:CGo C.size_t 和 C 中的数组大小为 int 类型。
【讨论】:
int 和 uint 值与整数文字进行比较(尽管尝试比较 int 和 uint variables 会导致“类型不匹配”错误) .
长度是数组类型的一部分;它必须计算为一个非负常数,该常数可由
int类型的值表示。可以使用内置函数len来发现数组 a 的长度。这些元素可以通过整数索引0到len(a)-1来寻址。数组类型总是一维的,但可以组合成多维类型。
我意识到说规范规定 X 可能有点循环,因为规范规定 Y,但因为长度不能超过 @ 的最大值987654326@,len 不可能返回一个 uint-exclusive 值,因为它返回一个负值。
【讨论】:
len()(和cap())返回int,因为这是用来索引切片和数组的(不是uint)。所以问题更多的是“当没有负索引时,为什么 Go 使用有符号整数来索引切片/数组?”。
答案很简单:计算索引是很常见的,如果以无符号整数进行此类计算,很容易下溢。对于 a 和 b 的 6 和 10 的无辜值,像 i := a-b+7 这样的无辜代码可能会产生 i == 4294967291。这样的索引可能会溢出您的切片。许多索引计算发生在 0 左右,并且使用无符号整数很难正确计算,这些错误隐藏在数学上完全合理和合理的公式后面。这既不安全也不方便。
这是基于经验的权衡:下溢往往发生在使用无符号整数进行的索引计算中,而如果使用有符号整数进行索引计算,则上溢则不太常见。
另外:在这些情况下使用无符号整数的好处基本上为零。
【讨论】:
有一个提案正在进行中“issue 31795 Go 2: change len, cap to
return untyped int if result is constant”
它可能包含在 Go 1.14(2010 年第一季度)中
我们应该能够毫无问题地为
len和cap做到这一点 - 确实如此 stdlib 中没有任何内容可以通过修改后的类型对其进行类型检查 检查显示
将 CL 179184 视为 PoC:这仍处于试验阶段。
作为peterSO 的noted below,这已关闭。
Robert Griesemer 解释:
正如您所指出的,使 len 始终无类型的问题是 结果。对于布尔值(以及字符串),大小是已知的,无论如何 一种布尔值(或字符串)。
我不确定这里的成本是否值得。今天有一个简单的 规则:
len(x)的类型为int。将类型更改为取决于x是什么 将以非正交方式与各种代码更改交互。例如, 在建议的语义下,此代码编译:const x string = "hello" func f(uintptr) ... f(len(x))但假设随后有人出现并希望能够修改
x为 测试或类似的东西,所以他们s/const/var/。这通常是相当的 安全,但现在f(len(x))调用无法进行类型检查,它将是 神秘的为什么它会起作用。此更改似乎可能会增加比删除更多的粗糙边缘。
【讨论】: