Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Blocks

Indentation

A line ending with : opens a block that holds the more indented lines after it. This works for struct, enum, union, trait, impl, mod, macro_rules!, fn, if, else, match, loop, while, for, unsafe, and async. Renk writes the braces, the , after fields and arms, and the ; after statements.

pub enum Shape:
    Circle(f64)
    Square(f64)

pub fn area(shape: &Shape) -> f64:
    match shape:
        Shape.Circle(radius) => 3.14 * radius * radius
        Shape.Square(side) => side * side

Any number of spaces is one level, as long as a block’s lines agree. Tabs are an error.

unsafe:, async:, and loop: open a block as a statement or a match arm body. As a let value or a call argument they need Rust braces, as in let task = async move { ... }. An extern block also needs braces.

A : block may keep Rust’s opening brace, as in fn main() { or fn main() {: followed by indented lines; no closing } is needed. A Rust { block is accepted anywhere, for example to keep a one-line body:

pub fn main():
    let value = { 1 + 2 }
    if value > 2 { println!("big") }

Semicolons

A statement ends at the end of its line. Renk infers the ; from the signature: a function returning a value keeps its last expression as the value, and a unit function ends it with ;. Write ; yourself only to discard a value that inference keeps.

Tails selected by #[cfg(...)] are each a value. One that is not already a block becomes one, since Rust takes attributes only on statements and blocks:

pub fn separator() -> char:
    #[cfg(unix)]
    '/'
    #[cfg(not(unix))]
    '\\'

becomes #[cfg(unix)] / { '/' } / #[cfg(not(unix))] / { '\\' }.

Function shorthand

fn name(...) -> T = expr is a function whose body is one expression. The expression can open a block, as in = match n: followed by indented arms.

pub fn twice(value: i32) -> i32 = value * 2

pub fn name(n: i32) -> &'static str = match n:
    0 => "zero"
    _ => "many"

Multi-line headers

A header continued over more indented lines, such as a where clause or a long condition, ends its last line with :. The body is indented one level past the header’s first line:

pub fn show[T](value: T) -> String
where
    T: std.fmt.Debug:
    format!("{value:?}")

pub fn check(a: bool, b: bool) -> bool:
    if a
        && b:
        return true
    false

A bound that rustfmt continues on a deeper line, as in Self::Item: / Clone + Default:, ends the header on that deeper line. A where clause of an item without a body ends at its last bound.

Groups

A line ending with ( or [, a struct literal or use tree ending with {, an unterminated string, or a trailing = continues until the group closes. The group’s contents are Rust syntax. .method() or ? lines at the same indent after it extend the expression.

pub fn total(values: &[i32]) -> i32:
    values
        .iter()
        .map(|value| value * 2)
        .sum()