Skip to content

Symbol decoder

Rust packs a lot of meaning into punctuation. Use this table when a line of AI-generated code looks like noise. Type in the filter box to find a symbol or a word, for example &, lifetime, or closure.

SymbolNameMeaningExample
&Shared reference (borrow)Borrow a value to read it. Many shared references can exist at the same time. In a type, &T means "a reference to a T".fn total(orders: &[Order]) -> u64
&mutMutable referenceBorrow a value to change it. While it exists, no other reference to the value can exist.fn add_line(order: &mut Order, line: Line)
*DereferenceRead or write the value behind a reference or smart pointer. Often not needed, because method calls dereference automatically.*count += 1;
'aLifetime parameterA name for how long a reference is valid. It describes, it does not change how long a value lives.fn longer<'a>(a: &'a str, b: &'a str) -> &'a str
'staticStatic lifetimeOn a reference: valid for the whole program (for example a string literal). As a bound T: 'static: the type holds no short-lived references. It does not mean "lives forever".const GREETING: &'static str = "Hello";
?Question mark operatorIf the value is an Err (or None), return it to the caller now. If not, unwrap the value and continue. Converts the error type with From.let text = fs::read_to_string(path)?;
name!Macro callA ! after a name calls a macro, not a function. Macros generate code at compile time.println!("{} orders", orders.len());
!Never typeIn a return type: the function never returns (it panics, loops forever, or exits the process).fn fail(msg: &str) -> ! { panic!("{msg}") }
::Path separatorSeparates modules, types, and associated items. Like . in a Java package name or a static member access.let orders = Vec::new();
->Return typeThe type that a function or closure returns. No -> means the function returns () (like void).fn count(orders: &[Order]) -> usize
=>Match armSeparates a pattern from the code that runs when the pattern matches. Like -> in a Java switch expression.Status::Paid => "paid",
|x|Closure parametersStarts a closure (a lambda). |o| o.total is Java o -> o.total(). || is a closure with no parameters.orders.iter().filter(|o| o.total_cents > 0)
..Range, or "the rest"Exclusive range a..b (end not included). In a pattern or struct literal: "ignore the other fields" or "take the other fields from here".for i in 0..3 {} // 0, 1, 2
..=Inclusive rangeA range that includes the end value. Also used in patterns.1..=5 => "small",
_Wildcard / placeholderIn a pattern: match anything and ignore it. In a type: "infer this". As a name prefix (_order): "unused on purpose".let ids: Vec<_> = orders.iter().map(|o| o.id).collect();
#[...]AttributeMetadata on the next item, like a Java annotation. #[derive(...)] generates trait implementations.#[derive(Debug, Clone, PartialEq)]
#![...]Inner attributeAn attribute that applies to the item it is inside (the whole module or crate), not to the next item.#![forbid(unsafe_code)]
<T>Generic type parameterA type parameter, as in Java. Rust generates a separate copy of the code for each type used (no type erasure).struct Page<T> { items: Vec<T>, total: usize }
<T: Trait>Trait boundT must implement the trait. Like <T extends Comparable<T>> in Java.fn largest<T: Ord>(items: &[T]) -> Option<&T>
dynTrait objectA value whose concrete type is known only at run time; calls go through a vtable. This is how every Java interface call works.let handlers: Vec<Box<dyn Handler>> = Vec::new();
implImplementation block, or "some type that implements"impl Type { } adds methods. impl Trait for Type { } implements an interface. impl Trait in a signature means "one concrete type that implements the trait".fn ids(&self) -> impl Iterator<Item = u64> + '_
asPrimitive cast, or renameConverts between number types. It can truncate or change the sign without an error. Also renames an import.let small = big as u8; // 300 becomes 44
mutMutableThe binding can change. Variables are immutable by default, the opposite of Java.let mut total = 0;
refBind by referenceIn a pattern: borrow the matched value instead of moving it. Modern code rarely needs it.if let Some(ref name) = customer.nickname {}
moveMove closureThe closure takes ownership of the variables that it uses. Needed for threads and async tasks.thread::spawn(move || process(orders));
Self / selfThe type / the receiverSelf is the type in the current impl block. self is the value a method is called on, like this.fn new(id: u64) -> Self { Self { id } }
r#"..."#Raw string literalA string with no escape processing. Useful for JSON, regular expressions, and Windows paths. Like a Java text block without escapes.let json = r#"{"id": 7}"#;
b"..."Byte string literalA byte array (&[u8; N]), not a UTF-8 str. b'a' is one byte.socket.write_all(b"PING\r\n")?;
1_000Digit separatorUnderscores in number literals are ignored. Same as in Java.let limit_cents = 1_000_000;
0u8Literal type suffixThe suffix gives the type of the literal: u8, i64, f32, usize, and so on.let retries = 3u32;
@Pattern bindingGive a name to a value and also test it against a pattern.n @ 1..=9 => format!("single digit {n}"),
'label:Loop labelNames a loop, so that break or continue can target an outer loop. Same idea as Java labels.'orders: for order in &orders { break 'orders; }
::<>TurbofishGives a generic type argument at the call site, when the compiler cannot infer it.let n = "42".parse::<u32>()?;
whereWhere clauseTrait bounds written after the signature, for readability. Same meaning as bounds in <...>.fn report<T>(items: &[T]) -> String where T: Display
unsafeUnsafe block or functionCode where you, not the compiler, must prove memory safety. Every unsafe block needs a // SAFETY: comment.unsafe { ptr.read() }
asyncAsync function or blockReturns a Future. Nothing runs until something awaits it (unlike CompletableFuture, which starts at once).async fn fetch_order(id: u64) -> Result<Order, Error>
.awaitAwaitWaits for a future to complete, without blocking the thread. A postfix keyword, so it chains: .await?.let order = fetch_order(7).await?;

If you remember only three, remember these. They appear in almost every function.

  1. &: “borrow, do not take”. A function that takes &T reads the value; the caller keeps it.
  2. ?: “if this failed, return the error now”. It is Rust’s version of exception propagation, and it is visible on every line that can fail.
  3. ! after a name: a macro call, not a function call. println!, vec!, format!, and assert_eq! are macros.
  • Read signatures first. In fn f(x: T), f takes ownership of x. In fn f(x: &T) it borrows x. In fn f(x: &mut T) it borrows x to change it. The body follows from that.
  • Read <...> and 'a last. Generic parameters and lifetimes are usually correct if the code compiles. Skip them on the first pass, and come back if the signature looks unusually complex.
  • Use your editor. With rust-analyzer, hover over a name to see its type, and turn on inlay hints to see the inferred types of let bindings. This helps more than any table.