First, let's take a look at below Go interview question:
package main
const s = "Go101.org"
// len(s) == 9
// 1 << 9 == 512
// 512 / 128 == 4
var a byte = 1 << len(s) / 128
var b byte = 1 << len(s[:]) / 128
func main() {
println(a, b)
}
What would be the output in your mind? The output would be 4 0
. Surprising?
Before getting to the output values, some concepts in Go need to be introduced and explained in more detail.
len()
len()
is a built-in function in Go to get the length of array, slice or string. There is one important statement about len() in Go specification.
For some arguments, such as a string literal or a simple array expression, the result can be a constant. See the Go language specification's "Length and capacity" section for details.
Reading further, what if the statement const s = "Go101.org”
is changed to var s = "Go101.org”
, what would be the output?
package main
var s = "Go101.org"
var a byte = 1 << len(s) / 128
var b byte = 1 << len(s[:]) / 128
func main() {
println(a, b)
}
The output would be 0 0
.
And if above code snippet is changed to below
package main
var s = [9]byte{'G', 'o', '1', '0', '1', '.', 'o', 'r', 'g'}
var a byte = 1 << len(s) / 128
var b byte = 1 << len(s[:]) / 128
func main() {
println(a, b)
}
The output would become 4 0
again.
There is another statement in the specification talking about len() and cap().
The expression len(s) is constant if s is a string constant. The expressions len(s) and cap(s) are constants if the type of s is an array or pointer to an array and the expression s does not contain channel receives or (non-constant) function calls; in this case s is not evaluated. Otherwise, invocations of len and cap are not constant and s is evaluated.
Hence in above code
var a byte = 1 << len(s) / 128
var b byte = 1 << len(s[:]) / 128
len(s)
in the first statement is a constant, while the one len(s[:])
is not a constant. This is the only difference about these two statements. The end result is 9 but one is constant and one is not.
bit operation
In Go specification, the description about bit operation is
The right operand in a shift expression must have integer type or be an untyped constant representable by a value of type uint. If the left operand of a non-constant shift expression is an untyped constant, it is first implicitly converted to the type it would assume if the shift expression were replaced by its left operand alone.
Based on the description, we can infer that 1 << len(s)
is a constant shift expression but 1 << len(s[:])
is a non-constant shift expression.
And now let's read more about constant shift expression.
If the left operand of a constant shift expression is an untyped constant, the result is an integer constant; otherwise it is a constant of the same type as the left operand, which must be of integer type.
For the statement var a byte = 1 << len(s) / 128
, since 1 << len(s)
is a constant shift expression, its result would be an integer constant which is 512 and its end result is 4 when divided by 128.
As for var b byte = 1 << len(s[:]) / 128
, since 1 << len(s[:])
is a non-constant shift expression, the left operand is 1 which is an untyped constant and will be treated as a byte type. Why byte type?
constant
Constant is some data value calculated during compilation. In Go, there are two types of constant: untyped constant and typed constant. According to the spec, literal values, true, false, iota and some constant expressions are untyped constant.
Where are typed constants from? There are two ways: explicit declaration or implicit conversion. For example
const a int32 = 23
const b float32 = 0.1
Untyped constant normally has a default type which is usually one of bool, rune, int, float64, complex128 or string. When the type of the untyped constant is needed, it would be the default type after implicit conversion.
Hence in statement var b byte = 1 << len(s[:]) / 128
, 1 would be implicitly converted to type byte, and 1 << len(s[:])
will have type byte as well. Since the max value for byte type is 255 and 512 overflows, hence it becomes 0. The end result of b will be 0.
Reference: https://mp.weixin.qq.com/s/fL51hHLyuEZVvsbLIddXGg