Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The << operator in Rust is the bitwise left shift operator. It shifts the binary representation of the left operand to the left by the number of bit positions specified by the right operand. During this operation, vacated least significant bits (LSBs) are filled with zeros, and most significant bits (MSBs) shifted beyond the bit-width of the left operand’s type are discarded.
let result = left_operand << right_operand;

Type Rules and Inference

Unlike many binary operators in Rust, the << operator does not require the left and right operands to be of the same type. The left operand determines the type of the evaluated result, while the right operand dictates the shift amount. While built-in implementations exist for all primitive integer types, custom types can also support the << operator by implementing the appropriate trait.
let base: u8 = 0b0000_0011; // Decimal 3
let shift_amount: i32 = 4;

// The result is of type `u8`, matching the left operand.
// 0b0000_0011 becomes 0b0011_0000
let shifted = base << shift_amount; 

Trait Implementation

Under the hood, the << operator is syntactic sugar for the std::ops::Shl trait.
pub trait Shl<Rhs = Self> {
    type Output;
    fn shl(self, rhs: Rhs) -> Self::Output;
}
When you write a << b, the compiler translates this to a.shl(b). Rust also provides the compound assignment operator <<=, which is backed by the std::ops::ShlAssign trait, allowing for in-place mutation.

Overflow and Panic Behavior

Rust enforces strict safety checks regarding the shift amount (the right operand) when using the << operator. An overflow condition occurs if the right operand is greater than or equal to the total number of bits in the left operand’s type, or if the right operand is a negative value (when using a signed integer type). The behavior during an overflow condition depends on the compilation profile:
  1. Debug Mode: The compiler inserts runtime checks. Shifting by the bit-width or greater, or by a negative amount, will cause a thread panic with the message attempt to shift left with overflow.
  2. Release Mode: Rust performs a masked shift (wrapping behavior). The shift amount is masked using a bitwise AND operation against the bit-width minus one (shift_amount & (bit_width - 1)). For example, shifting a u8 by 9 bits will actually shift it by 1 bit (9 & 7 == 1). For negative shift amounts, this masking yields a wrapped positive shift amount (e.g., shifting a u8 by -1 results in a shift of 7 bits, since -1 & 7 == 7).
To explicitly control overflow behavior without relying on compilation profiles, Rust provides dedicated methods on integer primitives. Unlike the << operator, which accepts signed integers and checks for negative values at runtime, these explicit methods strictly require a u32 for the shift amount. This type signature enforces a non-negative shift amount at compile-time, making runtime checks for negative values impossible and unnecessary.
let x: u8 = 1;

// Returns an Option: Some(result) if valid, None if the shift amount is >= bit-width.
// Passing a negative number here results in a compile-time type error, not a runtime None.
let checked = x.checked_shl(8_u32); 

// Masks the shift amount with (bit_width - 1)
let wrapping = x.wrapping_shl(8_u32); 

// Returns a tuple (result, boolean_indicating_if_overflow_occurred)
let (overflowing, did_overflow) = x.overflowing_shl(8_u32); 
Master Rust with Deep Grasping Methodology!Learn More