Rust borrowing and ownership typing practice
Borrowing is not hard to type because it is long. It is hard because &mut self is a shifted symbol, a lowercase word and a keyword-adjacent noun in eight characters, and because the ampersand appears in a position most languages never put a symbol in — immediately before a type.
Why the ampersand breaks your rhythm
In most curly-brace languages, symbols appear between things: an operator sits between two operands, a dot sits between a receiver and a method. Rust's & is different — it is a prefix, glued to whatever follows it, and it changes the meaning of a type rather than combining two values.
That matters for muscle memory because prefix symbols have no rhythmic setup. You do not arrive at & after a space the way you arrive at +. You have to decide it is coming before you start the word, which means the decision happens at the exact moment your fingers are already moving. That is where the pause shows up, and it is why an accuracy score alone does not capture the problem — most people type &mut correctly. They just take almost twice as long doing it.
The eight borrow shapes worth drilling
| Token | Reads as | Why it is awkward |
|---|---|---|
&self | shared method | Shift-7 then a word with no space. The most common signature in Rust and the one most often typed as `& self`. |
&mut self | mutating method | Two words after a symbol. The space between `&mut` and `self` is easy to drop and easy to double. |
&mut Vec<T> | mutable borrow of a collection | Symbol, keyword, type, angle bracket — four different key regions in one parameter. |
&str | string slice | Constantly confused with `String` at the keyboard level, not just the type level. |
&'a str | borrowed for lifetime 'a | An apostrophe inside a type. Nothing else in mainstream syntax looks like this. |
&[T] | slice | Prefix symbol immediately followed by a bracket, with no identifier to anchor on. |
ref | bind by reference in a pattern | Rare enough that it never becomes automatic, common enough to keep appearing. |
Rc<RefCell<T>> | shared, interior-mutable | Three closing brackets in a row, two of them angle. |
The three signatures you actually type
Almost all borrow typing in day-to-day Rust collapses into three shapes. If these are automatic, the rest follows.
impl Counter {
fn get(&self) -> u32 {
self.value
}
fn bump(&mut self) {
self.value += 1;
}
}
fn first_word(text: &str) -> &str {
text.split_whitespace().next().unwrap_or("")
}Notice that the third function has no lifetime annotation. Rust elides it: one input reference means the output borrows from that input. Knowing the elision rules is what stops you from typing 'a reflexively in places it is not needed — a habit that costs keystrokes and makes signatures harder to read.
When the apostrophe is not a string
A lifetime looks like an unterminated character literal, and plenty of tooling gets this wrong. SyntaxGym's own token scanner has a specific rule for it: 'a followed by anything other than a closing quote in the third position is a lifetime, not a literal. Without that rule, everything after the first lifetime in a signature would be treated as string content and silently excluded from analysis.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
struct Excerpt<'a> {
part: &'a str,
}The practical typing lesson: the apostrophe belongs to the lifetime name, not to a pair. Your fingers want to close it. Train them not to.
How to practise this
Work through the Borrowing pack in copy mode until the shapes are familiar, then switch to gap mode, which blanks out the borrow tokens specifically and makes you supply them from memory. Watch the hesitation section of the result screen rather than the WPM: if &mut self shows a median pause well above your session baseline, it is not yet in your hands, however accurate it looks.
The Lifetimes pack is a deliberate second step. Do not start there — lifetime annotation is much easier to type once the plain borrow shapes stop requiring attention.
Frequently asked questions
- Why does Rust use & when other languages do not?
- The ampersand marks a reference: access to a value without owning it. Languages with a garbage collector do not need the distinction at the syntax level because the runtime tracks ownership for you. Rust moves that bookkeeping into the type system, so it has to be visible in the source — which is why references show up in almost every function signature you write.
- What is the difference between &self and &mut self when typing?
- &self takes a shared borrow, so the method can read but not modify. &mut self takes an exclusive borrow and can modify. At the keyboard they differ by four characters and a space, which is exactly the kind of small difference that becomes a reflex only through repetition — and exactly the kind that a typing test measuring words per minute will never surface.
- Should I practise lifetimes before or after borrowing?
- After. Lifetime annotations attach to references, so every lifetime you type includes a borrow you have already had to type. Drilling lifetimes first means practising two unfamiliar shapes at once and learning neither cleanly.
- Is 'a a string in Rust?
- No. A leading apostrophe followed by an identifier is a lifetime name, such as 'a or 'static. A character literal is a single character between two apostrophes, such as 'x'. This distinction matters to editors and analysis tools, which will mask the rest of a line if they mistake one for the other.
Keep reading
- Rust typing practice: the full method
What makes Rust specifically awkward under the fingers, and the order to attack it in.
- Enum and match practice
The fat arrow and exhaustive matching — the next-most-typed Rust shapes after borrows.
- What SyntaxGym measures
Why hesitation is tracked separately from mistakes, and what each number means.
Try it on a real snippet
No account, nothing uploaded. Your results stay in this browser.