Ownership
And
Borrowing
By: Davis Silverman
Who is This Guy?
- Student / Technologist at The Humangeo Group
- Rust enthusiast for over 2 years.
- Knows about Ownership and Borrowing
What is Rust?
- Modern language, built on decades of PL research
- Safety of Garbage Collection, without the overhead
- Concurrent, built on a great type system
Why Use Rust?
- As a safe alternative to C, without sacrificing performance
- To write performance sensitive bits of code through FFI
- To feel superior to our coworkers
Copy and Clone
- Copy data does not move its data
- Copy data is generally any Plain Old Data type
- Clone is necessary when you do not want to move
- Most every time implements Clone
Rust Pointer Types
- Reference Types: &, &mut
- Library Types: Box<T>, Rc<T>
- Raw Pointers: *const, *mut
- Interior Mutability: Cell<T>, RefCell<T>
Box<T>
- Used to own its data
- Just a single owner allowed
fn main() {
let x: Box<i32> = Box::new(64); // allocates memory for one i32
} // x is deallocated here
Rc<T>
- Also an owned Data Structure
- Multiple owners allowed
- Runtime overhead
use std::rc::Rc;
fn main() {
let mut first = Rc::new(132);
let sec = first.clone(); // cheap to clone, bumps reference count
*Rc::make_mut(&mut first) *= 3; // Copy on Write
let third = sec.clone();
println!("{:?} {:?} {:?}", first, sec, third);
}
Raw Pointers
- Completely Unsafe to dereference
- Great for FFI or low level datastructures
fn main() {
let x = 5;
let raw = &x as *const i32;
let mut y = 10;
let raw_mut = &mut y as *mut i32;
println!("the value of raw_mut is: {:?}.", unsafe {*raw_mut});
}
Cell<T> and RefCell<T>
- Interior Mutability
- Used when you want transparent mutability in a datastructure
use std::cell::{Cell, RefCell};
fn main() {
let cell = Cell::new(36);
cell.set(cell.get() * 2);
let rcell = RefCell::new(37);
*rcell.borrow_mut() *= 3;
println!("cell: {:?} - rcell: {:?}", cell, rcell);
}
What is Ownership?
- Making sure resources can not be invalidated
- Ensures resources allocated and freed only once
- Obviates the need for garbage collection
- (semi) Affine types
Ownership
fn main() {
let v = vec![1,2,3]; // this Vec is owned by `v`
let v2 = v; // ownership of the Vec is transferred to v2
// println!("{:?}", v); // this will fail if uncommented.
}
Deterministic Destruction
fn main() {
let v = vec![1, 2, 3]; // this Vec is owned by `v`
println!("vector: {:?}", v); // actually borrows `v`
// v will be 'Dropped' here. at the end of the scope
}
What is Borrowing?
- Temporarily having read permissions to a resource
- Temporarily having write permissions to a resource
- Each borrow is for an exact section of code, the lifetime of the borrow
Shared Borrows
#[derive(Debug)]
struct Thing {
x: i32,
}
fn borrow_it(t: &Thing) {
println!("the value is {:?}!", t.x);
}
fn main() {
let t = Thing {x: 865};
borrow_it(&t);
println!("Can still use it: {:?}!", t);
}
- ∞ uses
- read-only access
Exclusive Borrows
fn change_it(t: &mut Thing) {
t.x *= 11;
}
fn main() {
let mut t = Thing { x: 3 };
change_it(&mut t);
println!("first try: {:?}", t);
let copy = &mut t;
// println!("CANT ACCESS t {:?}", t);
change_it(copy);
println!("can access the copy: {:?}", copy);
}
- Single use during its lifetime
- Read and write access
Named lifetimes
#[derive(Debug)]
enum Token<'a> {
Word(&'a str),
Other(&'a str)
}
fn tokenize_str<'a>(text: &'a str) -> Vec<Token<'a>> {
let mut result = vec![];
for cap in Regex::new(r"(\w+)|(\W+)").unwrap().captures_iter(text) {
let token = match cap.at(1) {
Some(word) => Token::Word(word),
None => Token::Other(cap.at(2).unwrap())
};
result.push(token);
}
result
}
fn main() {
let tokens = tokenize_str("the-sinistersnare");
println!("{:?}", tokens);
}
http://www.randomhacks.net/2014/09/19/rust-lifetimes-reckless-cxx/
Mutliple lifetimes
fn search<'a, 'b>(needle: &'a str, haystack: &'b str) -> Option<&'b str> {
let len = needle.len();
if haystack.chars().nth(0) == needle.chars().nth(0) {
Some(&haystack[..len])
} else if haystack.chars().nth(1) == needle.chars().nth(0) {
Some(&haystack[1..len+1])
} else {
None
}
}
fn main() {
let haystack = "hello, Rust DC!";
let res;
{
let needle = String::from("ello");
res = search(&needle, haystack);
}
match res {
Some(x) => println!("found {}", x),
None => println!("nothing found")
}
}
Lifetime Elision
fn print(s: &str); // elided
fn print<'a>(s: &'a str); // expanded
fn debug(lvl: uint, s: &str); // elided
fn debug<'a>(lvl: uint, s: &'a str); // expanded
fn substr(s: &str, until: uint) -> &str; // elided
fn substr<'a>(s: &'a str, until: uint) -> &'a str; // expanded
fn frob(s: &str, t: &str) -> &str; // ILLEGAL
fn frop<'a,'b>(s: &'a str, t: &'b str) -> &'? str
fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command
fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command
- You do not always need to type lifetime parameters
- lifetimes can be elided, never inferred
Pop Quiz
Does it run?
fn as_str(data: &u32) -> &str {
let s = format!("{}", data);
&s
}
Does it run?
fn main() {
let mut data = vec![1, 2, 3];
let x = &data[0];
data.push(4);
println!("{}", x);
}
Does it run?
struct Foo;
fn main() {
let mut a = Foo;
let mut b = Foo;
let mut x = &mut a;
let y = &*x;
x = &mut b;
}
Safety
ITERATOR INVALIDATION
let mut v = vec![1, 2, 3];
for i in &v {
println!("{}", i);
v.push(34);
}
- Mutating an iterator while reading from it
- Easy to do accidentally in C++
- Cant happen in Rust
USE AFTER FREE
let y: &i32;
{
let x = 5;
y = &x;
}
println!("{}", y);
- Accessing a resource after it has been deleted
- Cant happen in Rust
Advanced Lifetimes
'static
static FOO: &'static i32 = &2_300_200;
static BAR: &'static str = "FOREVER";
fn main() {
let loc: &'static str = "ALSO FOREVER";
println!("FOO: {:?} - BAR: {:?} - loc: {:?}", FOO, BAR, loc);
}
- Lifetime of the entire program
- baked into the data segment
Subtyping
fn get_it<'a, 'b: 'a>(_: &'a str) -> &'b str {
// string literals are `&'static str`s
// &'static str is a subtype of any 'a
"hello"
}
fn main() {
let t = String::from("unused");
println!("{:?}", get_it(&*t));
}
- The fact that some liftimes are greater than others
- 'a: 'b means that 'a contains 'b
Thanks!
- Find me @Sinistersnare
- Give talks!
- Questions?
OwnershipAndBorrowing
By Davis Silverman
OwnershipAndBorrowing
- 1,391