Dive into Rust

Variable Shadowing #

let mut guess = String::new();

io::stdin().read_line(&mut guess)
    .expect("Failed to read line");

let guess: u32 = guess.trim().parse()
    .expect("Please type a number!");

const CONSTANT: &str = "a constant expression, not the result of a function call computed at runtime";
let immutable_variable: &str = "variables are immutable by default";
let mut mutable_variable: u32 = 0;
let immutable_variable: &str = "shadowing the previous immutable_variable, which is bad";
let immutable_variable: u32 = 1;

Data Types #

Scalar Types #

Compound Types #

Control Flow #

Condition must be a bool. Nice!

Enum #

Rust's enum is actually a tagged union.

Generics #

Rust monomorphizes code that is using generics at compile time.

Traits #

Rust's traits is similar to interface in other languages.

Memory Management #

Rust does not use GC or RC. For values on the heap, it only allow one variable "own" a value at a time. Assignment, passing a value to function and returning a value move the "ownership". Also, Rust allows multiple immutable pointers (&) but only one mutable pointer (&mut), and restricts mixing immutable and mutable pointers to the same target. The basic idea is to keep the number of reference to a value to one, to make memory management easier for the compiler.

let s1 = String::from("A long long string");
let s2 = s1 + ".";

Conceptually s2 can be considered as a newly constructed immutable variable, but since the ownership moves from s1 to s2, and s1 becomes invalid afterwards, the compiler just need to appends "." to the end of the value, which is efficient.

Smart pointers can be used for reference counting. Smart pointers are structs satisfying Deref and Drop traits.

enum List {
    Cons(i32, Box<List>),

In the above example, Box<List> is a smart pointer. We use Box<List> to store the Box<List> data on the heap, otherwise Cons(i32, List) will result in infinite size on the stack, which causes Rust failed to construct the List enum.

To allow cons more than one lists from a same base list:

enum List {
    Cons(i32, Rc<List>),

Rc is another smart pointer for reference counting. It increases the reference counter on RC::clone(&l), and reduce the reference counter automatically when the related variable goes out of scope. When there are zero references, the value will be cleaned up.

Be aware that Rc only works in single-thread context. In multiple-threads context, use Arc instead.

In Rust, functions and struts working with references need lifetime annotation. However, Rust can infer function lifetime in simplest cases:

String literals have a 'static lifetime, which lives for the entire duration of the program.

let b;
    let a = "hi";
    b = a;
println!("{}", b); // prints "hi"

Lifetime annotation tells Rust compiler the lifetime of variables, but it cannot alter the lifetime.

Testing #

While Go use special function name TestXxx, Rust uses #[test] attribute annotation.

Unit tests are written in mod tests, and integration tests are put in the test directory.

Documentation Comments #

Three leading slashes /// with Markdown.

Similar to Python, Rust also supports doctest:

/// # Example
/// ```
/// let foo = "foo";
/// assert_eq!(foo, "foo");
/// ```

unsafe #

In the unsafe block (unsafe {}), you can: