Why does len() returned a signed value?

有些话、适合烂在心里 提交于 2020-08-02 05:48:16

问题


Go's builtin len() function returns a signed int. Why wasn't a uint used instead?

Is it ever possible for len() to return something negative?
As far as I can tell, the answer is no:

  • Arrays: "The number of elements is called the length and is never negative."
  • Slices: "At any time the following relationship holds: 0 <= len(s) <= cap(s)"
  • Maps "The number of map elements is called its length". (I couldn't find anything in the spec that explicitly restricts this to a nonnegative value, but it's difficult for me to understand how there could be fewer than 0 elements in a map)
  • Strings "A string value is a (possibly empty) sequence of bytes.... The length of a string s (its size in bytes) can be discovered using the built-in function len()" (Again, hard to see how a sequence could have a negative number of bytes)
  • Channels "number of elements queued in channel buffer (ditto)

回答1:


len() (and cap()) return int because that is what is used to index slices and arrays (not uint). So the question is more "Why does Go use signed integers to index slices/arrays when there are no negative indices?".

The answer is simple: It is common to compute an index and such computations tend to underflow much too easy if done in unsigned integers. Some innocent code like i := a-b+7 might yield i == 4294967291 for innocent values for aand b of 6 and 10. Such an index will probably overflow your slice. Lots of index calculations happen around 0 and are tricky to get right using unsigned integers and these bugs hide behind mathematically totally sensible and sound formulas. This is neither safe nor convenient.

This is a tradeoff based on experience: Underflow tends to happen often for index calculations done with unsigned ints while overflow is much less common if signed integers are used for index calculations.

Additionally: There is basically zero benefit from using unsigned integers in these cases.




回答2:


Length and capacity

The built-in functions len and cap take arguments of various types and return a result of type int. The implementation guarantees that the result always fits into an int.

Golang is strongly typed language, so if len() was uint then instead of:

i := 0 // int
if len(a) == i {
}  

you should write:

if len(a) == uint(i) {
}

or:

if int(len(a)) == i {
}

Also See:

uint either 32 or 64 bits
int same size as uint
uintptr an unsigned integer large enough to store the uninterpreted bits of a pointer value

Also for compatibility with C: CGo the C.size_t and size of array in C is of type int.




回答3:


There is a proposal in progress "issue 31795 Go 2: change len, cap to return untyped int if result is constant"

It might be included for Go 1.14 (Q1 2010)

we should be able to do it for len and cap without problems - and indeed there aren't any in the stdlib as a type-checking it via a modified type checker shows

See CL 179184 as a PoC: this is still experimental.


As noted below by peterSO, this has been closed.

Robert Griesemer explains:

As you noted, the problem with making len always untyped is the size of the result.
For booleans (and also strings) the size is known, no matter what kind of boolean (or string).

Russ Cox added:

I am not sure the costs here are worth the benefit. Today there is a simple rule: len(x) has type int.
Changing the type to depend on what x is will interact in non-orthogonal ways with various code changes.
For example, under the proposed semantics, this code compiles:

const x string = "hello"
func f(uintptr)
...
f(len(x))

but suppose then someone comes along and wants to be able to modify x for testing or something like that, so they s/const/var/.
That's usually fairly safe, but now the f(len(x)) call fails to type-check, and it will be mysterious why it ever worked.

This change seems like it might add more rough edges than it removes.




回答4:


From the spec:

The length is part of the array's type; it must evaluate to a non-negative constant representable by a value of type int. The length of array a can be discovered using the built-in function len. The elements can be addressed by integer indices 0 through len(a)-1. Array types are always one-dimensional but may be composed to form multi-dimensional types.

I realize it's maybe a little circular to say the spec dictates X because the spec dictates Y, but since the length can't exceed the maximum value of an int, it's equally as impossible for len to return a uint-exclusive value as for it to return a negative value.



来源:https://stackoverflow.com/questions/39088945/why-does-len-returned-a-signed-value

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!