Today's Question:  What does your personal desk look like?        GIVE A SHOUT

Understand more about Go basics with one interview question

  sonic0002        2020-10-10 02:52:19       3,835        0    

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

LEN()  SHIFT OPERATION  CONSTANT  GOLANG 

Share on Facebook  Share on Twitter  Share on Weibo  Share on Reddit 

  RELATED


  0 COMMENT


No comment for this article.