Back to home
Rust programming language logo

Rust Online Compiler

Practice Rust right here — no installs, no signups.

Rust Compiler
Output
Code runs on the Play with Coding execution engine — your code is saved locally for next time.

About the Rust online compiler

Rust gives you C-level performance with compile-time memory safety and no garbage collector. The trade is a strict compiler — but Rust's error messages are the friendliest of any systems language, usually telling you the exact fix. This online Rust compiler shows those messages in full.

Practise ownership and borrowing, pattern matching with match, Option and Result instead of null and exceptions, structs and impl blocks, and iterators. Fighting the borrow checker for an hour teaches more about memory than a semester of theory.

  • Understanding ownership, moves and borrows
  • Practising match and exhaustive pattern handling
  • Learning Option/Result error handling
  • Testing iterator chains without a local toolchain

Rust sample programs you can run right now

Copy any snippet into the editor above and press Run. Each one is short on purpose — retype it from memory afterwards.

Ownership and borrowing

fn length(s: &String) -> usize { s.len() }

fn main() {
    let name = String::from("Play with Coding");
    println!("{} chars", length(&name));
    println!("still usable: {}", name);
}

Passing &name borrows the value instead of moving it, so name is still valid afterwards.

Pattern matching on Option

fn main() {
    let nums = vec![10, 20, 30];
    match nums.get(5) {
        Some(v) => println!("found {}", v),
        None => println!("index out of range"),
    }
}

get returns Option instead of panicking, and match forces you to handle both cases.

Common Rust errors and how to fix them

borrow of moved value

Why: The value was moved into another binding or function and is no longer owned here.

Fix: Borrow with & instead of moving, or .clone() when a copy is acceptable.

cannot borrow `x` as mutable more than once at a time

Why: Two mutable references overlap.

Fix: Shorten the first borrow's scope so it ends before the second begins.

mismatched types: expected `&str`, found `String`

Why: String and &str are different types.

Fix: Use &value or value.as_str() to convert.

Rust syntax cheatsheet

ConceptSyntax
Entry pointfn main() { }
Printprintln!("{}", x);
Mutable variablelet mut x = 5;
Vectorlet v = vec![1, 2, 3];
Struct + implstruct P; impl P { fn go(&self) {} }
Matchmatch v { Some(x) => .., None => .. }

Rust compiler FAQs

Can I use external crates?

No — snippets compile without Cargo dependencies, so stick to the standard library.

Why does the compiler reject working-looking code?

Usually the borrow checker. Read the help: line in the error — it almost always names the exact fix.

Keep going after the compiler

Running snippets builds speed; the 17-chapter course builds understanding. Work through the Rust chapters, take the quiz, then claim your certificate.

Other compilers: JavaScript compiler, TypeScript compiler, Python 3 compiler, Java compiler, C compiler, C++ compiler, Go compiler, HTML compiler, CSS compiler, SQLite compiler

Rust tutorial: five steps from blank editor to working program

These steps introduce the ideas that make Rust different: immutability by default, ownership and borrowing, Option and Result instead of null and exceptions, and pattern matching.

  1. 1. Variables are immutable unless you say otherwise

    let binds a value that cannot change; let mut allows reassignment. Making mutation explicit is what lets the compiler reason about your program.

    fn main() {
        let name = "Rust";
        let mut count = 0;
        count += 1;
        println!("{name} {count}");
    }
  2. 2. Ownership: one owner at a time

    Assigning a heap value moves it. The old binding becomes unusable, which is how Rust guarantees there is no double free without a garbage collector.

    fn main() {
        let a = String::from("code");
        let b = a.clone(); // clone, because a move would end a's life
        println!("{a} {b}");
    }
  3. 3. Borrow instead of moving

    & lends a read-only reference and &mut lends an exclusive one. You may have many readers or one writer, never both — that rule eliminates data races.

    fn length(s: &String) -> usize { s.len() }
    
    fn main() {
        let s = String::from("compiler");
        println!("{} {}", length(&s), s);
    }
  4. 4. Option and Result replace null and exceptions

    A value that may be missing is Option<T>; an operation that may fail is Result<T, E>. The compiler forces you to handle both cases.

    fn main() {
        let nums = vec![1, 2, 3];
        match nums.get(5) {
            Some(v) => println!("found {v}"),
            None => println!("out of range"),
        }
    }
  5. 5. Match exhaustively

    match must cover every variant, so adding a new enum case turns every unhandled site into a compile error rather than a silent bug.

    enum Status { Draft, Published, Archived }
    
    fn label(s: Status) -> &'static str {
        match s {
            Status::Draft => "draft",
            Status::Published => "published",
            Status::Archived => "archived",
        }
    }
    
    fn main() { println!("{}", label(Status::Published)); }

Practice exercises with solutions

Try each one in the editor above before opening the solution — the struggle is where the learning happens.

Beginner

Print the sum of the numbers 1 to 10 using an iterator.

Hint: (1..=10).sum::<i32>() does it in one expression.

Show solution
fn main() {
    let total: i32 = (1..=10).sum();
    println!("{total}");
}
Intermediate

Filter a vector of marks down to the passing ones and print them.

Hint: iter().filter().collect() into a Vec<&i32> or copied() for Vec<i32>.

Show solution
fn main() {
    let marks = vec![42, 87, 13, 96];
    let passed: Vec<i32> = marks.into_iter().filter(|m| *m >= 50).collect();
    println!("{passed:?}");
}
Advanced

Write a function returning Result and handle both outcomes at the call site.

Hint: Return Result<f64, String> and match on it.

Show solution
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 { return Err("division by zero".to_string()); }
    Ok(a / b)
}

fn main() {
    match divide(10.0, 0.0) {
        Ok(v) => println!("{v}"),
        Err(e) => println!("error: {e}"),
    }
}

Why learn Rust?

Rust prevents null dereferences, data races and use-after-free at compile time, so a class of bugs that plagues C and C++ simply cannot occur in safe Rust.

It reaches C-level performance without a garbage collector, which makes it viable for systems work, WebAssembly and embedded targets alike.

What Rust is used for

  • Systems programming and command-line tools
  • WebAssembly modules for the browser
  • Networking services where latency spikes are unacceptable
  • Embedded and operating-system components

Ready for structured practice? The 17-chapter Rust course takes these ideas one at a time, with a quiz and a certificate at the end.