tutorials/rust/todo-list-borrow/src/main.rs

126 lines
3.3 KiB
Rust

fn copyable() {
// All numeric primitives, signed and unsigned are copyable
let a: i64 = 10;
let b = a;
let c: f32 = 0.1;
let d = c;
println!("a and c are not moved: {} {}", a, c);
// Bools too
let e = true;
let f = e;
println!("Bools are copyable too: {}", e);
// Char's and string slices are copyable too, BUT NOT Strings
let g: char = 'g';
let h = g;
let i = "string slices are copyable";
let j = i;
println!("chars are copyable: {} aaaand {}", g, i);
// Arrays and array slices too
let k = [1, 2, 3];
let l = k;
// Get a slice of the first entry in the k array
let m = &k[0..1];
let n = m;
println!("Arrays and array slices are copyable: {:?} {:?}", k, m);
// Tuples too
let o = (1, "str");
let p = o;
println!("Tuples are copyable {:?}", o);
// That was the types that are copyable by default
// We can also implement Copy on our own types as long
// as they hold copyable types themselves
struct Point {
x: i32,
y: i32,
}
impl Copy for Point {}
impl Clone for Point { fn clone(&self) -> Point { *self } }
let q = Point { x: 1, y: 10 };
let r = q;
println!("We made a copyable struct! {}/{}", q.x, q.y);
// Phew! that was some black magic. Copy and Clone are `traits` that are built into the language
// Traits are basically interfaces that you can implement on your types
// You can create them yourselves too, which we'll get to in a future post
// There is an easier way to make a type copyable though:
#[derive(Copy, Clone, Debug)]
struct Point3D {
x: i32,
y: i32,
z: i32,
}
let s = Point3D { x: 1, y: -20, z: 30 };
let t = s;
println!("Point3D is now copyable, and the Debug trait let's us print it easily {:?}", s);
}
fn borrowing() {
#[derive(Clone, Debug)]
struct Point {
x: i32,
y: i32,
}
let a = Point {
x: 0,
y: 0,
};
// As discussed this would cause a `moved value` error
// let b = a;
// let c = a;
// Borrowing is fine an unlimited amount of times though
let b = &a;
let c = &a;
// But only for as long as the reference lives
// Rust is block scoped, basically any time you see {} it's a block
{
let d = Point { x: 0, y: 0 };
// This is totally fine
let e = &d;
// But here, at the end of this block, d goes out of scope
}
// So this would fail
// let f = &d;
// You can also borrow a value mutably, but then the borrower has
// exclusive rights to mutate the value until it goes out of scope
let mut f = Point { x: 0, y: 0 };
let g = &mut f;
// This would fail
// let h = &mut f;
// Even the owner can't mutate itself without causing an error
// f.x = 1;
// This means that mutable borrows are mostly practical when passing something to a function
fn pointifier(point: &mut Point, multiply_by: i32) {
point.x *= multiply_by;
point.y *= multiply_by;
}
let mut h = Point { x: 1, y: 2 };
pointifier(&mut h, 20);
// once the pointifier function has finished, the borrow ends, and h is mutable again
h.x -= 1;
println!("Point {:?}", h);
}
fn main() {
copyable();
borrowing();
}