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 << nis roughlyx * 2^nx >> nis roughlyx / 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 >>
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 << 1means shift the bits of5left by 1 place5 << 2means 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
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:
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 = 1Write = 2Execute = 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
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
MB = <<
GB = <<
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
Comparisons
| Concept | Meaning | Best used for |
|---|---|---|
x << n | Shift bits left by n | powers of two, masks, flags |
x >> n | Shift bits right by n | extracting fields, halving powers of two |
x * 2 | Multiply arithmetically | clearer general-purpose math |
x / 2 | Divide arithmetically | clearer general-purpose math |
Shift vs multiplication/division
x << 1
is similar to:
x *
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 << nis likex * 2^nx >> nis likex / 2^n
1 << nis 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
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.
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
Keep learning
Related questions
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Calling Functions Across Files in the Same Go Package
Learn how Go uses packages across multiple files, why functions may appear undefined, and how to organize code correctly.