Question

Go Bitwise Shift Operators: Understanding << and >>

gobitwise-operators

Question

Could someone please explain how the << and >> operators are used in Go? I assume they are similar to shift operators in other programming languages, but I would like to understand what they do and how to use them correctly.

Short Answer

By the end of this page, you will understand how Go's left shift (<<) and right shift (>>) operators work, how they change integer values, when they are useful, and which common mistakes beginners should avoid when working with bitwise operations.

Concept

The << and >> operators in Go are bit shift operators.

  • << shifts bits to the left
  • >> shifts bits to the right

These operators work on integer values at the binary level.

What shifting means

Computers store integers as bits (0 and 1). For example:

5 = 00000101

If you shift 5 left by 1:

5 << 1

the bits move one position to the left:

00000101 -> 00001010

That becomes 10.

If you shift 5 right by 1:

5 >> 1

the bits move one position to the right:

00000101 -> 00000010

That becomes 2.

Why this matters

Bit shifting is useful because it is a compact way to:

  • multiply or divide by powers of two
  • work with binary flags
  • encode or decode packed values
  • manipulate low-level data such as bytes, masks, and permissions

Basic rule of thumb

For positive integers:

  • x << n is roughly x * 2^n
  • x >> n is roughly x / 2^n

Examples:

4 << 1 // 8
4 << 2 // 16
20 >> 1 // 10
20 >> 2 // 5

Important Go-specific idea

In Go, shift operators are defined for integer types, and the amount you shift by matters.

For example:

var x uint = 3
fmt.Println(x << 2) // 12

This means: move the bits of x left by 2 positions.

Go is stricter than some languages, so type handling around shifts can matter, especially with typed vs untyped constants.

Mental Model

Think of a binary number as a row of boxes holding 0 or 1.

5  = 0 1 0 1

A left shift << pushes every bit one or more boxes to the left and fills the empty spaces on the right with 0.

A right shift >> pushes every bit to the right.

Simple analogy

Imagine digits on a conveyor belt:

  • shifting left moves everything left, making the number bigger for positive values
  • shifting right moves everything right, making the number smaller for positive values

Another useful mental shortcut:

  • << = multiply by 2 again and again
  • >> = divide by 2 again and again

This shortcut works well for non-negative integers.

For example:

3 << 1 // 6
3 << 2 // 12
16 >> 1 // 8
16 >> 3 // 2
Take Quiz

Syntax and Examples

Basic syntax

value << shiftAmount
value >> shiftAmount

Example 1: Left shift

package main

import "fmt"

func main() {
    x := 5
    fmt.Println(x << 1) // 10
    fmt.Println(x << 2) // 20
}

Explanation

  • 5 << 1 means shift the bits of 5 left by 1 place
  • 5 << 2 means shift the bits left by 2 places
  • each left shift by 1 doubles the value for positive integers

Example 2: Right shift

package main

import "fmt"

func main() {
    x := 20
    fmt.Println(x >> 1) // 10
    fmt.Println(x >> 2) // 5
}

Explanation

  • 20 >> 1 shifts right by 1, which halves the number
  • 20 >> 2 shifts right by 2, which divides by 4

Example 3: Visualizing bits

package main

import "fmt"

func main() {
    var x uint8 = 5
    fmt.Printf("%08b\n", x)      // 00000101
    fmt.Printf("%08b\n", x<<1)   // 00001010
    fmt.Printf("%08b\n", x>>1)   // 00000010
}

This example prints the binary representation so you can see the bit movement directly.

Example 4: Powers of two

package main

import "fmt"

func main() {
    fmt.Println(1 << 0) // 1
    fmt.Println(1 << 1) // 2
    fmt.Println(1 << 2) // 4
    fmt.Println(1 << 3) // 8
}

This is a common pattern when creating bit masks or powers of two.

Step by Step Execution

Consider this code:

package main

import "fmt"

func main() {
    x := 6
    y := x << 1
    z := y >> 2

    fmt.Println(x)
    fmt.Println(y)
    fmt.Println(z)
}

Step-by-step

1. x := 6

6 in binary is:

00000110

2. y := x << 1

Shift left by 1:

00000110 -> 00001100

That is 12.

So now:

y == 12

3. z := y >> 2

Now shift 12 right by 2:

12 in binary:

00001100

Shift right twice:

00001100 -> 00000011

That is 3.

So now:

z == 3

4. Output

The program prints:

6
12
3

Key takeaway

Shifting changes the bit pattern directly. For positive integers:

  • left shift grows the value
  • right shift reduces the value

Real World Use Cases

1. Working with flags and permissions

Bit shifts are often used to create individual flags.

const (
    Read = 1 << 0
    Write = 1 << 1
    Execute = 1 << 2
)

These become:

  • Read = 1
  • Write = 2
  • Execute = 4

You can combine them with bitwise OR.

2. Building bit masks

mask := 1 << 3 // 8

This sets the 4th bit position.

Useful in:

  • permissions
  • feature toggles
  • protocol flags
  • compact state storage

3. Encoding data

Sometimes multiple small values are packed into one integer.

value := (3 << 4) | 2

This stores one value in higher bits and another in lower bits.

4. Processing bytes and binary formats

When reading file formats, network packets, or device data, shifts help extract fields.

high := b >> 4
low := b & 0x0F

5. Fast power-of-two calculations

size := 1 << 10 // 1024

This is common for buffer sizes, memory units, and capacity calculations.

Take Quiz

Real Codebase Usage

In real Go codebases, shifts are usually not used for basic math. They are more commonly used for binary structure and intent.

Common patterns

Guarded flag definitions

const (
    FlagActive = 1 << iota
    FlagAdmin
    FlagVerified
)

This creates powers of two automatically.

Validation before shifting

Developers often make sure values are valid before applying shifts, especially when the shift amount comes from input.

if shift < 0 {
    return fmt.Errorf("invalid shift amount")
}

Packing and unpacking fields

id := uint32(15)
kind := uint32(3)
packed := (kind << 16) | id

Byte and protocol parsing

version := header >> 4

Configuration constants

const KB = 1 << 10
const MB = 1 << 20
const GB = 1 << 30

When teams avoid shifts

Developers may avoid bit shifts when plain multiplication or division is clearer:

result := n * 4

is often easier to read than:

result := n << 2

unless the code is specifically about bits, masks, bytes, or flags.

Common Mistakes

1. Thinking shifts are only for math

Shifts can multiply or divide by powers of two, but their real purpose is bit manipulation.

If your code is ordinary business logic, normal arithmetic may be clearer.

2. Forgetting that bits are being moved

Beginners may write code without understanding the binary effect.

x := 5
fmt.Println(x << 1) // 10

This is not magic multiplication. The bits are actually shifted.

3. Using shifts with the wrong type expectations

Go is strict about types. Integer type matters.

var x uint8 = 255
fmt.Println(x << 1)

This can surprise beginners because the result may not behave the way they expect if they are thinking only in terms of fixed-width storage. Always pay attention to the operand types and resulting values.

4. Confusing left shift and right shift

x := 8
fmt.Println(x << 1) // 16
fmt.Println(x >> 1) // 4

A good memory trick:

  • left shift usually makes positive numbers larger
  • right shift usually makes positive numbers smaller

5. Assuming right shift always means exact division

For positive powers of two, it behaves like division by 2^n.

But bit shifting is still a bit-level operation, so you should think in terms of bits, especially for signed values.

6. Writing unreadable code

This is valid:

size := 1 << 10

This may be less clear in ordinary logic:

items := count << 1

Prefer the clearest expression for the situation.

7. Forgetting operator intent in flag definitions

Broken example:

const (
    A = 1
    B = 2
    C = 3
)

This is not suitable for unique bit flags because 3 overlaps existing bits.

Correct approach:

const (
    A = 1 << 0
    B = 1 << 1
    C = 1 << 2
)

Comparisons

ConceptMeaningBest used for
x << nShift bits left by npowers of two, masks, flags
x >> nShift bits right by nextracting fields, halving powers of two
x * 2Multiply arithmeticallyclearer general-purpose math
x / 2Divide arithmeticallyclearer general-purpose math

Shift vs multiplication/division

x << 1

is similar to:

x * 2

And:

x >> 1

is similar to:

x / 2

For many business calculations, * and / are easier to read.

Shift operators vs other bitwise operators

OperatorPurpose
&AND: keep bits that are set in both values
``
^XOR: set bits that differ
&^AND NOT: clear selected bits
<<shift left
>>shift right

Shifts often appear together with these operators when working with masks and flags.

Take Quiz

Cheat Sheet

Quick syntax

x << n // shift left by n bits
x >> n // shift right by n bits

Quick rules

  • Use shifts with integer values
  • << moves bits left
  • >> moves bits right
  • For positive integers:
    • x << n is like x * 2^n
    • x >> n is like x / 2^n
  • 1 << n is a common way to create powers of two and bit masks

Common examples

5 << 1  // 10
5 << 2  // 20
20 >> 1 // 10
20 >> 2 // 5
1 << 3  // 8

Common flag pattern

const (
    Read = 1 << 0
    Write = 1 << 1
    Exec = 1 << 2
)

Binary printing

fmt.Printf("%08b\n", x)

Good use cases

  • bit masks
  • flags
  • protocol fields
  • byte manipulation
  • powers of two

Readability tip

Use normal arithmetic when that better communicates intent.

FAQ

What does << mean in Go?

<< is the left shift operator. It moves the bits of a number to the left by a given number of positions.

What does >> mean in Go?

>> is the right shift operator. It moves the bits of a number to the right.

Is x << 1 the same as x * 2?

For positive integers, it behaves like multiplying by 2. But technically it is shifting bits, not performing general arithmetic.

Is x >> 1 the same as x / 2?

For positive integers, it behaves like dividing by 2. It is still a bitwise operation, so think carefully when signed values are involved.

Why do Go developers use 1 << n so often?

It is a clean way to create powers of two, especially for flags and bit masks.

When should I use shifts instead of multiplication or division?

Use shifts when the code is about bits, masks, flags, bytes, or binary formats. Use normal arithmetic when you want clarity in everyday calculations.

Can I use shift operators with floating-point numbers?

No. Shift operators are for integer values, not floating-point types.

Take Quiz

Mini Project

Description

Build a small Go program that models user permissions using bit flags. This demonstrates a practical use of << by creating unique permission values and then checking whether a user has a specific permission.

Goal

Create and inspect a permission value using bit shifts and bitwise operations.

Requirements

  • Define at least three permissions using 1 << n
  • Combine multiple permissions into one value
  • Check whether a specific permission is enabled
  • Print the permission value and the check results
Take Quiz

Keep learning

Related questions

View more