fn main() { string(); ownership_functions(); references(); slices(); } fn string() { { let s = String::from("hello"); // s is valid from this point forward // do stuff with s } // this scope is now over, and s is no // longer valid let mut s = String::from("hello"); s.push_str(", world!"); // push_str() appends a literal to a String println!("{}", s); // This will print `hello, world!` // Memory validation let s1 = String::from("hello"); let s2 = s1; //println!("{}, world!", s1); // s1 is no longer valid as ownership of the string pointer is on s2 let s1 = String::from("hello"); let s2 = s1.clone(); // Now both are valid println!("s1 = {}, s2 = {}", s1, s2); } fn ownership_functions() { 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 let x = 5; // x comes into scope makes_copy(x); // x would move into the function, let s1 = gives_ownership(); // gives_ownership moves its return // value into s1 let s2 = String::from("hello"); // s2 comes into scope let s3 = takes_and_gives_back(s2); // s2 is moved into // takes_and_gives_back, which also // moves its return value into s3 // Here, s3 goes out of scope and is dropped. s2 was moved, so nothing // happens. s1 goes out of scope and is dropped. } 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. fn gives_ownership() -> String { // gives_ownership will move its // return value into the function // that calls it let some_string = String::from("yours"); // some_string comes into scope some_string // some_string is returned and // moves out to the calling // function } // This function takes a String and returns one fn takes_and_gives_back(a_string: String) -> String { // a_string comes into // scope a_string // a_string is returned and moves out to the calling function } //=== fn references() { let s1 = String::from("hello"); let len = calculate_length(&s1); println!("The length of '{}' is {}.", s1, len); let mut s = String::from("hello"); let r1 = &mut s; //s = String::from("Test"); println!("{}, {}", r1, r1); //we can't even use s as the function would borrow from an already borrowed variable } fn calculate_length(s: &String) -> usize { s.len() } //=== fn slices() { let mut s = String::from("Hello world!"); let word = first_word(&s); //s.clear(); // We have borrowed s in word, so this is invalid action println!("the first word is {}", word); } 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 is better as argument than string, they serve the same purpose when immutable fn better_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[..] }