# Ownership ## Basic Rules 1. Each value in Rust has an owner 1. There can only be one owner at a time 1. When owner goes out of scope, the value will be dropped # Scope Range in which a variable is valid, normally indicated by a {inside is a scope} Variables are only valid between the time they are declared and the end of a scope # Shallow Copy This causes a move (shallow copy) to s2 where s2 has the value previously owned by s1 ```rust let s1 = String::from("hello"); // s1 is no longer the owner variable of the string, move has occured to s2 let s2 = s1; // this would not work because s1 is no longer valid/has a pointer to the string println!("{s1}"); ``` ## Deep Copy This is a deep copy this only happens by default with primitive values Rust will not create a deep copy by default, therefore copies are cheap in terms of performance This will only copy the part on the stack, this is the same functionality as let y = x.clone() ```rust let x = 5; let y = x; ``` ### Deep Copy Heap If you want a deep copy for things on both the stack and heap then use .clone() method Indication that some code executing has a high performance cost ```rust let s1 = String::from("hello"); let s2 = s1.clone(); println!("s1 = {s1}, s2 = {s2}"); ``` ## Copy Trait Will not be allowed to be implemented if Drop trait has already been implemented trying to implement a copy trait with a drop trait will cause a complimation error Drop is only used when it needs something special to leave scope Any group of simple scalar values implement copy Such as: - Integers like u32 - Booleans with true/false values - All Float Point Values like f32, f64 - Char - Tuples only if they only contain values that implement copy themselves - ## Assignment When you assign a completely new value to something on the heap then then the drop function qill be called on the old data on the heap automaitcally ```rust let mut s = String::from("hello"); // drop called on the old "hello" s = String::from("ahoy"); // outputs ahoy println!("{s}, world!"); ``` # Function Ownership This is the same as the move/shallow copy ```rust fn main() { let s = String::from("hello"); // s comes into scope takes_ownership(s); // s's value moves into the function... // ... and so is no longer valid here // if s was called here the s variable would no longer be valid/in scope let x = 5; // x comes into scope makes_copy(x); // x would move into the function, // but i32 is Copy, so it's okay to still // use x afterward // x is allowed to be used here because of low cost to copy **see deep copy heap } // Here, x goes out of scope, then s. But because s's value was moved, nothing // special happens. fn takes_ownership(some_string: String) { // some_string comes into scope println!("{some_string}"); } // Here, some_string goes out of scope and `drop` is called. The backing // memory is freed. fn makes_copy(some_integer: i32) { // some_integer comes into scope println!("{some_integer}"); } // Here, some_integer goes out of scope. Nothing special happens. ``` # Returning Multiple Values using a tuple ```rust fn main() { let s1 = String::from("hello"); let (s2, len) = calculate_length(s1); // s1 gives up ownership to funct println!("The length of '{s2}' is {len}."); } fn calculate_length(s: String) -> (String, usize) { let length = s.len(); // len() returns the length of a String (s, length) // s gives up ownership to return a value } ``` # References ## Rules 1. At any given time, you can have either one mutable reference or any number of immutable references. 1. References must always be valid Giving access to a variable without transfering ownership/moving it Can have unlimited read-only/immutable references this is created by ```rust let var_name: &var_to_borrow_value ``` ## Mutable References Can only have 1 mutable reference this is created by ```rust let var_name: &mut var_to_borrow_value ``` This prevents three bad behavoirs - Two or more pointers access the same data at the same time. - At least one of the pointers is being used to write to the data. - There’s no mechanism being used to synchronize access to the data. Also allowed ```rust { let r1 = &mut s; } // r1 goes out of scope here, so we can make a new reference with no problems. let r2 = &mut s; ``` ## Mixing References NOT ALLOWED IN ONE SCOPE ONLY 1 Mutable Reference PER SCOPE OR UNLIMITED IMMUTABLE PER SCOPE REFERNECE SCOPE ENDS WHEN IT IS LAST USED BAD CODE EXAMPLE ```rust let r1 = &s; // no problem let r2 = &s; // no problem let r3 = &mut s; // BIG PROBLEM ``` OK code, not great, only possible becasue r1 and r2 are out of scope when r3 is declared ```rust let mut s = String::from("hello"); let r1 = &s; // no problem let r2 = &s; // no problem println!("{r1} and {r2}"); // variables r1 and r2 will not be used after this point let r3 = &mut s; // no problem println!("{r3}"); ``` ## Dangling Reference Compiler will guarantee that this cannot happen This happens when a pointer refers to an address in memory that was freed by another variable and possibly used by something else ```rust fn dangle() -> &String { // dangle returns a reference to a String let s = String::from("hello"); // s is a new String &s // we return a reference to the String, s } // Here, s goes out of scope, and is dropped. Its memory goes away. // Danger! ``` Fixed Code ```rust fn dangle() -> String { // dangle returns a String let s = String::from("hello"); // s is a new String s } // Here, s goes out of scope, and ownership is transfered and nothing other than the s namespcae is deallocated ``` ## Slices Let you reference a continuous sequence of elements The sequence does not have an owner is reference only it is considered a slice which is a kind of reference example use want to find the first word in a string words are seperated by a space This has a problem the usize only makes sense for the reference to thee string as it currently is, if the value the string was references changes than usize makes no sense/is not connected to the state of the string/out of sync ```rust // dont want ownership so reference is fine, returns usize this is the index of the space fn first_word(s: &String) -> usize { // convert string to an array of bytes so that we can go through it let bytes = s.as_bytes(); // create iterator for bytes, method that returns each element in an array // enumerate, returns it as a part of a tuple instead which is destructed // i is the index and titem is the iteam itself to compair in the if statement // need to be a reference to that ownership doesnt change for (i, &item) in bytes.iter().enumerate() { if item == b' ' { // index of the space return i; } } // if there are no spaces in the string then return the whole length s.len() } ``` ### String Slices Slices must occur at the utf-8 character boundaries, slices at the character within a charcter's boundaries will cause an error This is constructed by ```rust let var_name = &string_to_refer[start_index..end_index] ``` .. is range syntx in rust ```rust let a = [..2]; // range starts at 0 and goes to 2 let b = [0..2]; // the same as a in terms of range let c = [3..len]; // goes from 3 to the end let d = [3..]; // the same as c in terms of range let f = &s[..]; // the whole range of s, where s is some string ``` Example ```rust let s = String::from("hello world"); let hello = &s[0..5]; // hello let world = &s[6..11]; // world ``` Revised Example with String Slice The value returned by this function is guaranteed to be related to the vairable passed in If it is not valid the complier will catch it and throw out a borrowing rule error (two reference types mixing) ```rust fn first_word(s: &String) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[0..i]; } } &s[..] } ``` ### String Literal Slices ```rust let s: &str = "hello World" ``` This is the same type as a string slice bbut it is a special kind that points to a specific part of the binary ### String Slices as a parameter to improve the function you can change the reference form &String to &str to also handle string literals without sacrifices to the base functionality this takes advantage of deref coercions ```rust fn first_word(s: &str) -> &str ``` ### Example Perfected ```rust fn main() { let my_string = String::from("hello world"); // `first_word` works on slices of `String`s, whether partial or whole let word = first_word(&my_string[0..6]); let word = first_word(&my_string[..]); // `first_word` also works on references to `String`s, which are equivalent // to whole slices of `String`s let word = first_word(&my_string); let my_string_literal = "hello world"; // `first_word` works on slices of string literals, whether partial or whole let word = first_word(&my_string_literal[0..6]); let word = first_word(&my_string_literal[..]); // Because string literals *are* string slices already, // this works too, without the slice syntax! let word = first_word(my_string_literal); } fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[0..i]; } } &s[..] } ``` ### Other Slices This is a more general use of a slice ```rust let a = [1, 2, 3, 4, 5]; let slice = &a[1..3]; assert_eq!(slice, &[2, 3]); ``` This has a slice type of &[i32]