Last active
March 2, 2016 07:29
-
-
Save koyedele/22d49ac7501f22447e03 to your computer and use it in GitHub Desktop.
Learning Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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