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(); }