Shift operators

January 25, 2024

Operators

The right operand in a shift expression must have integer type or be an untyped constant representable by a value of type uint.

A bunch of examples demonstrating this follow in the spec, so I won’t provide my own.

… 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.

So what are we actually talking about here? This:

m := int64(3)
x := 5 << m // A non-constant shift expression, with an untyped const as the left operand

So what is x’s type here? That’s what this sentence is describing when it says “it is first implicitly converted to the type it would assume if the shift expression were replaced by its left operand alone”.

In other words, x’s type should match the type of the expression:

y := 5

And indeed it does:

var m = int64(3)
x := 5 << m
y := 5
fmt.Printf("%T %T\n", x, y) // int int
var a [1024]byte
var s uint = 33

// The results of the following examples are given for 64-bit ints.
var i = 1<<s                   // 1 has type int
var j int32 = 1<<s             // 1 has type int32; j == 0
var k = uint64(1<<s)           // 1 has type uint64; k == 1<<33
var m int = 1.0<<s             // 1.0 has type int; m == 1<<33
var n = 1.0<<s == j            // 1.0 has type int32; n == true
var o = 1<<s == 2<<s           // 1 and 2 have type int; o == false
var p = 1<<s == 1<<33          // 1 has type int; p == true
var u = 1.0<<s                 // illegal: 1.0 has type float64, cannot shift
var u1 = 1.0<<s != 0           // illegal: 1.0 has type float64, cannot shift
var u2 = 1<<s != 1.0           // illegal: 1 has type float64, cannot shift
var v1 float32 = 1<<s          // illegal: 1 has type float32, cannot shift
var v2 = string(1<<s)          // illegal: 1 is converted to a string, cannot shift
var w int64 = 1.0<<33          // 1.0<<33 is a constant shift expression; w == 1<<33
var x = a[1.0<<s]              // panics: 1.0 has type int, but 1<<33 overflows array bounds
var b = make([]byte, 1.0<<s)   // 1.0 has type int; len(b) == 1<<33

// The results of the following examples are given for 32-bit ints,
// which means the shifts will overflow.
var mm int = 1.0<<s            // 1.0 has type int; mm == 0
var oo = 1<<s == 2<<s          // 1 and 2 have type int; oo == true
var pp = 1<<s == 1<<33         // illegal: 1 has type int, but 1<<33 overflows int
var xx = a[1.0<<s]             // 1.0 has type int; xx == a[0]
var bb = make([]byte, 1.0<<s)  // 1.0 has type int; len(bb) == 0

Quotes from The Go Programming Language Specification Version of August 2, 2023


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Operators

Operators Operators combine operands into expressions. Nice. I love a concise description/definition. Especially after the confusion that was yesterday’s post about loose and exact unification. Expression = UnaryExpr | Expression binary_op Expression . UnaryExpr = PrimaryExpr | unary_op UnaryExpr . binary_op = "||" | "&&" | rel_op | add_op | mul_op . rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" . add_op = "+" | "-" | "|" | "^" .


Floating-point operators

Floating-point operators For floating-point and complex numbers, +x is the same as x, while -x is the negation of x. The result of a floating-point or complex division by zero is not specified beyond the IEEE-754 standard; whether a run-time panic occurs is implementation-specific. I find this to be quite interesting. An implementation may choose to panic, or not, if you attempt to divide a floating-point or complex number by zero.


Arithmetic operators

Arithmetic operators Arithmetic operators apply to numeric values and yield a result of the same type as the first operand. The four standard arithmetic operators (+, -, *, /) apply to integer, floating-point, and complex types; + also applies to strings. The bitwise logical and shift operators apply to integers only. + sum integers, floats, complex values, strings - difference integers, floats, complex values * product integers, floats, complex values / quotient integers, floats, complex values % remainder integers & bitwise AND integers | bitwise OR integers ^ bitwise XOR integers &^ bit clear (AND NOT) integers << left shift integer << integer >= 0 >> right shift integer >> integer >= 0 There should be nothing surprising here.