Skip to content

← Ground Rules: Values, Types, Control Flow step 4 of 24

Easy Primitives

Numeric literals: suffixes, underscores, other bases

Apply the bit mask 0xFF_00_FF_00 to each input and return the result.

pub fn decode_masks(flags: &[i64]) -> Vec<u32>

Mask in i64 — so the low 32 bits of a negative input participate exactly as they do in two’s complement — then hand back the u32 that survives. The masked value can never exceed 0xFF00FF00, so that last step always fits.

0 gives 0. 4294967295 (all 32 bits set) gives 4278255360, which is the mask itself. -1 gives the same, because -1 is all-ones in two’s complement.

Literal syntax is where inference becomes visible

A bare 42 in Rust does not have a type yet. It has a type variable that inference will pin down from context — and if nothing pins it down, it defaults to i32. That is why let x = 42; gives an i32 and let x: u8 = 42; gives a u8 with no cast in sight.

You can also pin it yourself, in the literal:

42u8        // suffix: this is a u8
42_i64      // underscore before the suffix is allowed and often clearer
1_000_000   // underscores anywhere, purely for the reader
0xFF        // hex          = 255
0o77        // octal        = 63
0b1010_1100 // binary       = 172, grouped into nibbles
b'A'        // byte literal = 65u8

Underscores are ignored entirely by the compiler. Group them however the domain wants: 1_000_000 for a count, 0xFF_00_FF_00 for a byte-per-byte mask, 0b1010_1100 for nibbles. Writing the mask as 4278255360 is technically the same number and tells the reader nothing at all — you cannot see which bytes are selected without reaching for a calculator.

The specific lesson: a const, in hex, with underscores

const MASK: i64 = 0xFF_00_FF_00;

Three separate improvements over the starter’s let mask = 4278255360 as i64;:

  1. const — this is a compile-time constant, not a runtime binding. It has no address, it is inlined, and its SCREAMING_SNAKE_CASE name tells the reader instantly that it never changes. Constants require an explicit type; inference is not allowed to guess for them.
  2. Hex with underscoresFF 00 FF 00 is visibly “keep byte 3, drop byte 2, keep byte 1, drop byte 0”.
  3. No cast — the annotation : i64 already makes the literal an i64. Casting it again is what clippy’s unnecessary_cast is complaining about in the starter, and the lint is right: 4278255360 as i64 implies a conversion is happening when none is.

Two float lints, since you are here

Both are on by default and both catch beginner numeric literals:

  • approx_constant fires when you write 3.14159 instead of std::f64::consts::PI. The hand-typed version is less accurate and less readable, and the constant is right there.
  • excessive_precision fires when you write more digits than the type can hold — 1.123_456_789_012_345_678_9f32 is a lie, because f32 cannot represent it. The compiler rounds silently; the lint tells you it happened.

There is also unreadable_literal, which would push 1000000 toward 1_000_000 — but it is a pedantic lint, off by default, so nothing on this site will make you group your digits. Do it anyway.