Skip to content

Instantly share code, notes, and snippets.

@koyedele
Last active March 2, 2016 07:29
Show Gist options
  • Save koyedele/22d49ac7501f22447e03 to your computer and use it in GitHub Desktop.
Save koyedele/22d49ac7501f22447e03 to your computer and use it in GitHub Desktop.
Learning Rust
Key idea #1: Variable bindings in Rust "have ownership" of what they're bound to.
let x = 5; // 'x' "OWNS" the value 5
let v = vec![1,2,3,4,5]; // 'v' "OWNS" the vector datastructure which contains the values '1,2,3,4,5'
Ownership is a serious matter - even functions "own" their parameters, so this WILL NOT compile:
fn main() {
fn somefunc(x: i32, v: Vec<i32>) -> i32 {
// somefunc "owns" x and v once they are bound as parameters
12
}
// if you do this
let v = vec![1,2,3];
let y = somefunc(32, v);
// and then you try this:
println!("{}", v[0]); // compiler yells "error: use of moved value: `v`"
}
Key idea #2: Rust has move semantics
let v = vec![1,2,3,4,5]; // 'v' "OWNS" the vector as above
let v1 = v; // now 'v1' OWNS the data structure that v used to own.
// The data has been MOVED to v1 from v.
// What does 'v' own now? Nothing!
println!("v[0] is: {}", v[0]);// The compiler yells at us here. 'v' doesn't own anything anymore!
Bottomline: Once you give a reference to a variable to another binding, either through assignment or as function arguments,
that other binding owns the data.
Key idea #3: Rust ensures that there is EXACTLY one binding to any given resource (This is the effect of Key idea #2).
// Think "single static assignment form". If you want more than one reference to a variable
// there must still be one owner, and the others MUST borrow.
Key idea #4: References to variables can be borrowed. So, this will compile:
fn main() {
fn somefunc(x: i32, v: &Vec<i32>) -> i32 {
// somefunc "owns" x and has borrowed a reference to v
// once they are bound as parameters
12
}
let v = vec![1,2,3]; // v is the owner of the data
let y = somefunc(32, &v); // take a reference to the data owned by v
// now you can try this:
println!("{}", v[0]); // no errors; v is still the owner
}
Key idea #5: Borrowed references CANNOT by mutated; if you want to be able to modify the values,
you must take MUTABLE REFERENCES. So this WILL NOT compile:
fn main() {
fn somefunc(x: i32, v: &Vec<i32>) -> i32 {
let added = x + v[0];
v[0] = added;
added
}
let v = vec![1,2,3];
let y = somefunc(12, &v); // ERROR: cannot borrow immutable borrowed content `*v` as mutable
}
This will compile:
fn main() {
// NOTE: the second arg to the function is
// "a mutable reference to a vector of 32-bit ints which we're calling v"
fn somefunc(x: i32, v: &mut Vec<i32>) -> i32 {
let added = x + v[0];
v[0] = added;
added
}
let mut v = vec![1,2,3]; // we declare the vector v points to as mutable
let y = somefunc(12, &mut v); // we must now take a "mutable reference to the mutable vector v"
}
Key idea #6: You can't borrow willy-nilly. The rules are:
- one or more references (&T) to a resource,
- exactly one mutable reference (&mut T).
So, this won't work:
fn main() {
let mut x = 5; // the value the binding x points to is mutable
let y = &mut x; // take a "mutable reference to a mutable x"
*y += 1; // y is a reference so add 1 to the value of it's dereference
println!("x = {}", x); // Aha! Compiler yells: cannot borrow `x` as immutable because it is also borrowed as mutable
// RECALL: Functions OWN the data that is passed to them! (In truth, println! is a macro but it expands
// to a function). So in effect, println! acquires an immutable reference to x, which y has also acquired
// as mutable - a violation of Rule 2.
}
Key idea #7: Borrowing is tied to the scope that the borrow is valid for.
Recall the example of Key idea #6. The way to fix it is to make the mutable borrow of x go out of scope before
we try to borrow it again. Thus, this will compile:
fn main() {
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("x = {}", x);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment