Syntax#
Rust’s grammar is C-shaped with curly braces, semicolons, and
explicit blocks; on top of that sit pattern-matching arms,
? propagation, lifetime markers, and attributes
(#[...]). Source files start with module declarations
(mod, use), then the body. rustfmt is the only
formatter; never argues style.
/types`; for operators, see Operators.
fn greet(name: &str) {
println!("hello, {name}");
}
fn main() {
greet("operator");
}
Identifiers#
Unicode letters, digits, and underscores; cannot start with a
digit. Convention: snake_case for functions and variables,
CamelCase for types and traits, UPPER_SNAKE for
constants, _leading_underscore for “intentionally unused”.
let user_count = 0;
const MAX_RETRY: u32 = 5;
struct HttpClient;
trait Listener {}
let _unused = compute(); // silences the "unused" lint
Keywords#
as async await break const continue crate dyn else enum extern
false fn for if impl in let loop match mod move mut pub ref
return Self self static struct super trait true type unsafe
use where while
Reserved: abstract become box do final macro override priv
try typeof unsized virtual yield.
Literals#
let n: i32 = 42;
let big = 1_000_000; // separators allowed
let x = 0xff_u32; // suffix sets the type
let o = 0o755;
let b = 0b1010_0001;
let pi = 3.14_f64;
let e = 6.022e23_f64;
let s: &str = "hello"; // string slice (UTF-8)
let owned = String::from("hi");
let raw = r"no \n escapes"; // raw string
let multi = "this
spans lines";
let c: char = 'A'; // UTF-32 code point
let b: u8 = b'A'; // byte literal
let bs = b"bytes"; // byte string
let t = true;
let n: i32 = 0;
let none: Option<i32> = None; // Option is the operator's "nullable"
Statements#
Most Rust constructs are expressions. A trailing ;
turns an expression into a statement (suppressing its value);
the last expression in a block (without ;) is the block’s
value.
let x = 1 + 2; // statement
let y = {
let n = 10;
n * 2 // expression value of the block
};
// y == 20
fn double(n: i32) -> i32 {
n * 2 // implicit return; no `;`
}
Expressions#
Almost everything: arithmetic, function calls, blocks, if,
match, loop, range (a..b), closures (|x| x+1),
the try operator (?), method chains, and macro invocations.
let n = if x > 0 { x } else { -x };
let label = match n % 2 { 0 => "even", _ => "odd" };
let doubled: Vec<i32> = (0..5).map(|i| i * 2).collect();
let path = std::env::var("HOME")?; // ? early-returns the Err
Attributes#
Annotations on items (#[attr]) or inner attributes on the
enclosing item (#![attr]). Used for metadata, conditional
compilation, derives, and lints.
#[derive(Debug, Clone)]
struct User { name: String }
#[allow(dead_code)]
fn experimental() {}
#[cfg(target_os = "linux")]
fn platform_probe() {}
#![warn(missing_docs)] // applies to the whole crate
Modules#
A crate is the compilation unit (a binary or library); a
module is a namespace within it. mod name; declares a
module; use path::item; brings names into scope.
mod scan; // pulls in scan.rs or scan/mod.rs
use std::collections::HashMap;
use crate::scan::Probe;
See Runtime for the module / crate / workspace model.
Comments#
Line
//and block/* ... */(block comments do nest). Doc comments (///for the next item,//!for the enclosing module) producerustdocoutput.