Rust: Basic Syntax

So, I've been playing with Rust lately, and I've noticed that some really basic things just aren't explained in the docs (or at least not anywhere that's easy to find). This is my attempt to make up for this shortcoming.

Borrowed Parameters

So, you've got a borrowed parameter (perhaps a mutable one for a somewhat C-style API?). Now you want to work with the actual value. How do you do that? If you want to call a function on a struct, that's pretty straightforward: it's the same regardless of borrowing or not. But what if it's something simpler, like an f32? Well, borrowed things are more like C pointers than C++ references. So, you do it like this:

rust_borrow.rs

1
2
3
fn foo(t: &mut f32) {
    *t += 3.14;
}

Yep, it's a dereference operator, just like in C.

Non-Borrowed, Mutable Parameters

rust_mutable_param.rs

1
2
3
fn foo(mut t: f32) {
    t += 2.0;
}

Yes, this can actually be useful on occasion, typically when dealing with a struct that gets moved. That said, the one time so far that I used this construct, I ended up changing it to something less weird.

Types of Borrowed Parameters

Wondering what the difference between mut foo: &f32 and foo: &mut f32 is? Here you go:

rust_silly_mutability.rs

fn foo<'a>(mut t: &'a i32, v: &'a i32) {
    t = v;
    println!("In foo, t = {}", t);
}

fn bar(t: &mut i32) {
    *t += 1;
    println!("In bar, t = {}", t);
}

fn main() {
    let mut t = 0;
    let v = 42;
    foo(&t, &v);
    bar(&mut t);
    println!("In main, t = {}", t);
}

What's that? That didn't help at all? You're even more confused now? OK, let's dissect that a bit. First off, if you're unfamiliar with the &'somerandomthing syntax, that's a lifetime specification. Essentially, if you have &'a var1 and &'a var2, then var1 and var2 will have the same lifetime. You usually don't need to specify this, but sometimes the compiler needs a little help.

So, foo takes a mutable, borrowed reference to an i32 called t and an immutable, borrowed reference to an i32 called v. It then sets t to point to whatever v points to. Thus, foo prints In foo, t = 42.

bar takes a borrowed reference to a mutable i32 called t. It then increments the value that t points to. Thus, bar prints In bar, t = 1.

Since bar took a reference to a mutable value, t has changed in main. Thus, main prints In main, t = 1.

Does mut t: &i32 seem useless to you? It does to me, but I haven't been writing Rust code for very long.