R
RUSTY YELLOW PAGES

.Punctuation


Explanation

. has three related but distinct uses, all sharing the same "reach into what's on my left" shape.

Field access reads a named field off a struct: value.field. Method calls chain the same token: value.method(args), and a chain of calls reads left to right, each one operating on the previous call's result (text.trim().to_lowercase().len()). Tuple indexing uses . followed by an integer literal — .0, .1, and so on — to reach a field by position instead of by name, and it applies identically to a plain tuple (pair.0) and to a tuple struct (point.0), since a tuple struct's fields are addressed the same positional way a plain tuple's are.

. is lexically overloaded with the decimal point in a floating-point literal (3.14) — the tokenizer disambiguates by what follows: a digit after . continues a float literal, while an identifier or another digit used as a tuple index follows the field-access/tuple-indexing rule instead. . is also unrelated to .. and ..= (range syntax) and to :: (path separator, see ::) — each is its own token, not . repeated or combined with another character.

Both field access and method calls auto-deref: writing my_box.len() or my_reference.field follows through as many &/* layers as needed to find a matching method or field on the pointee, without the caller writing (*my_box).len() by hand. This mechanism is Deref-based and is covered from the token's own angle on the * page rather than repeated here.

Usage examples

Field access, tuple indexing, and method chaining

struct Point { x: f64, y: f64 }

let p = Point { x: 1.0, y: 2.0 };
println!("{}", p.x);       // <- `.` here is field access

let pair = (10, "ten");
println!("{}", pair.0);    // <- `.` here is tuple indexing, not field access

let text = "  Hello  ";
println!("{}", text.trim().to_lowercase()); // <- `.` chains two method calls left to right

Creating a new object

A builder's methods each take and return Self, so . chains them into one expression that reads as a sequence of configuration steps ending in a final, fully-built value.

struct RequestBuilder {
    url: String,
    timeout_ms: u32,
}

impl RequestBuilder {
    fn new(url: impl Into<String>) -> Self {
        RequestBuilder { url: url.into(), timeout_ms: 5000 }
    }

    fn timeout_ms(mut self, ms: u32) -> Self {
        self.timeout_ms = ms;
        self
    }
}

let request = RequestBuilder::new("https://api.example.com")
    .timeout_ms(2000); // <- `.` chains onto the value the previous call returned

Each builder method returning Self is what makes chaining with . possible at all — the Rust Design Patterns book covers this shape as a way to assemble a many-field value step by step, without needing a temporary mutable variable at the call site.

Branching on data (pattern matching)

Reaching for .0/.1 instead of a full destructuring pattern works well when only one field of a tuple or tuple struct is needed — matching every field just to discard most of them adds ceremony a positional dot access avoids.

struct Rgb(u8, u8, u8);

fn red_channel(color: &Rgb) -> u8 {
    color.0 // <- tuple indexing: pulls one field without matching all three
}

// contrast: matching is worth it once every field is actually used
fn describe(color: &Rgb) -> String {
    match *color {
        Rgb(r, g, b) => format!("#{r:02x}{g:02x}{b:02x}"),
    }
}

.0 is the more direct choice whenever the rest of the tuple genuinely isn't needed at that call site, while a match/let pattern reads more clearly once more than one field is being pulled out, since naming each field there beats a run of numbered dot accesses.

Explanation

Embedded support: Full

. means exactly the same thing under #![no_std] — field access, method calls, and tuple indexing are core grammar with no std dependency, and auto-deref works identically. The idiom this token enables that's distinctly embedded is the svd2rust "write closure" pattern used by most peripheral-access crates: a register write takes a closure, and the closure body chains several . method calls — one per bit-field — before the register is actually written in one go.

Usage examples

Chaining register field writes through a PAC closure

gpioa.odr.write(|w| w.odr5().set_bit()); // <- `.` chains field-accessor calls on the register writer `w`

Reading a driver's field through auto-deref

struct Sensor { calibration: u16 }

fn offset(sensor: &Sensor) -> u16 {
    sensor.calibration // <- `.` auto-derefs through the `&` to reach the field
}