len is a Go predefined identifier and also a Go builtin predefined function, through the go doc tool we can check the doc of the len function as follows.


The len function is not new even to Go beginners, as it is a frequently used function in everyday Go development. len’s arguments are mainly variables of composite data types, such as arrays (including pointer types for executing arrays), slices, strings, channels, etc. The returned result is the length of these composite data variables, which is a int type value. I won’t go into too much detail, and you’re probably familiar with it. What I will say is that there is one thing about the len function that you may not be familiar with or care about, and that is when the result of the len(s) expression is a constant and when the result is a variable. Don’t overlook this detail, as it will probably make your program output results you didn’t expect, and I’ll give you an example below.
This example comes from a go quiz tweeted by the author of Go 101, whose original question looked like this.
Ask what the output of the above example is!
Let’s give you five minutes to think about it! … …
Okay, thinking time is over! Presumably you’ve already run this quiz in the Go playground or the Go compiler and got the correct answer: 0 128 .
Whether you derived it yourself or got it by running the source code, now you tell me why the above quiz outputs 0 128!
I guess many people are as confused as I was at first!
 Isn’t the return value of len an int? Why is the assignment to p or q of type byte not reported as a compile error?
 Why is p 0 and q 128? … …
Here is my analysis, for your reference, to see if it can answer your questions.
First of all, the only difference between p and q is that the expression on the right side of the q variable declaration directly uses the length of the array x: len(x), while the argument of the len function in the expression on the right side of the p variable declaration is [8]int{f()}, which is a temporary array and contains an element assignment operation with a function call. Obviously this difference determines the final result.
For questions about the details of the Go language, the official Go language spec is the most authoritative reference . Open the Go language spec and locate the section Length and capacity, where we see the following description of the result of evaluating the len(s) expression.


The general meaning of this passage is that, for the expression len(s)
 if s is a string constant, then the expression len(s) is also a constant (constant).
 If s is an array or a pointer to an array and the expression s does not contain a channel receive call or a nonconstant (nonconstant) function call , then the len(s) expression is a constant, in which case we do not need to evaluate s.
 In the rest of the cases, the result of len(s) is not a constant, and we need to evaluate s.
How do we understand the “nonconstant function call” in the second article? The Go spec gives an example.
In the examples, the righthand side of both c4 and c5 statements are len function calls to arrays. s in len(s) in c4 is [10]float64{imag(2i)}, which is an array that contains an imag function call, but since the argument to the imag is a constant, the call to the imag returns a constant as well, not a single nonconstant function call, so the len expression on the righthand side of the c4 declaration statement is essentially a constant.
The s in len(s) in c5 is [10]float64{imag(z)}, which is also an array, and also contains an imag function call, the difference is that the argument to the imag is a variable of type complex128, so the imag function call is a nonconstant function call, and the return value cannot be used as a So for such s, the value of the len expression will not be a constant either, so the value of the len expression cannot be used as the initial value of the constant c5.
With the above knowledge in mind, let’s look at the variables p and q in the quiz above. let’s look at the variable q first.
We see that the argument to the len function in the initial expression to the right of the variable q is the array x, and that the expression (x) does not contain any function calls, which satisfies the condition that len(s) is a constant, and so len(x) is a constant, which means that the declaration statement of q above is equivalent to the following statement.


The right side of the equals sign of the equals statement is an untyped integer literal value constant, this constant value is calculated at compile time , the value is 128, the variable q of type byte can store the next 128 this value, so q is equal to 128.
Let’s go back to the variable p.


Our len expression here contains a function call to f(). Is f() a nonconstant function call? Test it with the following code to find out.
We see that f() is not a constant function call like an imag, so the len(s) in the p variable declaration is not a constant. Then that len(s) expression requires an expression evaluation process when assigning a value to the variable p.
So how does the expression ( 1 « len([8]int{f()}) ) / 2 look like? This is a left shift operator («), and the operand to the left of this operator is the untyped constant 1. Is it the default type int of the untyped constant or the variable type byte to the left of the equal sign?
We have to resort to the go spec again. The go spec has a paragraph on leftshift/rightshift expressions reads as follows.


The general idea is that the right operand of a shift expression must be an integer type or an untyped constant that can be represented by a value of type uint. If the left operand of a nonconstant shift expression is an untyped constant, it is first implicitly converted to a type, what type? It is the type of the left operand after replacing the entire shift expression with the left operand.
This last sentence is too convoluted, let’s give an example to illustrate, the following example from go spec.
The righthand side of the declaration statement for variable j is a shift expression, and the shift expression is a nonconstant shift expression, where the type of the untyped constant 1 is determined how? According to the above statement, the type of 1 in this expression is equivalent to the type of 1 in the following statement.


We see that 1 is an untyped constant, and its final type depends on the type of the variable on the left side of the statement, so 1 is of type int32, and eventually 1<<s
is of type int32 (go spec: Arithmetic operators apply to numeric values and yield a result of the same type as the first operand).
Okay, let’s go back to the shift expression in variable p. This expression is also not a constant shift expression. Thus the type of 1 in it is equivalent to the type of 1 in the following statement.


That is, 1, an untyped constant, is of type byte, so 1 « len([8]int{f()}) overflows after shifting 8 bits to the left, and the result is 0. So the righthand expression of the variable p evaluates to 0, and the p value is 0.
The Go language is known for its simplicity, but there are not a lot of syntactic details in Go. This go quiz topic is a great test of your ability to grasp the details of the Go language syntax!