// // Examples related to ownership, also introducing String. // // Georg Hopp <georg@steffers.org> // // Copyright © 2019 Georg Hopp // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // fn main() { concat(); move_variable(); clone_variable(); let s = String::from("hello"); // s comes into scope take_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); // the scalar value has the Copy trait and // lives on the stack and thus is still // valid here. let _s1 = gives_ownership(); // move the return value into _s1 let s2 = String::from("hello"); // s2 comes into scope let _s3 = takes_and_gives(s2); // s2 is moved into function, which in // turn moves the return value into _s3. let s1 = String::from("hello"); // s1 comes into scope. let len = calculate_length(&s1); // A reference to s1 is given to a // calculate_length which effectively is // not s1 itself but another pointer to // s1… which is the reason that we still // can use it below. let _another_s = &s1; // again only a reference which does not // take ownership, thus s1 can still be // used below. println!("The length of '{}' is {}.", s1, len); // Passing values as reference to a function is called borrowing. A // borrowed value can't be changed. change(&s1); // but we can force this… which is probably not the best of ideas most // of the time… let mut s_mut = String::from("hello"); change_mutable(&mut s_mut); // but you can have only one mutable reference of a value in a single // scope. The following would fail with: // cannot borrow `s_mut` as mutable more than once at a time second // mutable borrow occurs here // let r1 = &mut s_mut; // let r2 = &mut s_mut; // println!("{}, {}", r1, r2); // We also can't have an immutable reference while we have a mutable one. // Look on Page 98 for an explanation. // The scope of references is not the whole block they are introduced in // but goes only until their last usage. Thus if you first have an // immutable reference but never use it after a mutable reference is // declared, that would be ok… At all this is kind of confusing and very // Mozzilaish. :D // Now we demonstrate string slices… let s4 = String::from("hello world"); let s_slice = first_word(&s4); // working with an mutable reference like with s4.clear() will not // compile at this point because we already have and use later on an // immutable reference. println!("The slice was: {}", s_slice); // not that string literals are slices. They are immutable references of // the programs TEXT segment. Thats the reason why they are immutable. // Thus try generic_first_word… println!("First word on literal: {}", generic_first_word("hello world")); println!("First word on String: {}", generic_first_word(&s4[..])); } // x and s go out of scope but nothing happens for s because this function // has no longer the ownership of s. // s3 goes out of scope and is dropped. s2 was moved and s1 is dropped. fn concat() { let mut s = String::from("hello"); s.push_str(", world!"); println!("{}", s); } fn move_variable() { let s1 = String::from("hello"); let s2 = s1; // does not copy data but only the String structure. // when using s1 below we get an error that a moved value was borrowed. println!("{}, world!", s2); } fn clone_variable() { let s1 = String::from("hello"); let s2 = s1.clone(); // this time both are valid. println!("s1 = {}, s2 = {}", s1, s2) } fn take_ownership(some_string: String) { // some_string comes into scope println!("{}", some_string); } // some_string goes out of scope and «drop» is called, thus memory freed. fn makes_copy(some_integer: i32) { // some integer comes into scope println!("{}", some_integer); } // Here, some_integer goes out of scope but because it was a copy and on the // stack nothing special happens… beside that stack space is freed. fn gives_ownership() -> String { // this will move the return value into the // calling function. let some_string = String::from("hello"); // some_string comes into scope some_string } fn takes_and_gives(a_string: String) -> String { // a_string comes into scope a_string // and is returned and moved // to the calling function. } // a_string goes out of scope but nothing happens as it is moved. fn calculate_length(s: &String) -> usize { // s comes into scope. It is a // reference. References do not // take ownership of the underlying // value which is the String in // main. s.len() } // Here s goes out of scope but because it has no ownership of the String // nothing happens. fn change(_some_string: &String) { // the following would give this error: // `_some_string` is a `&` reference, so the data it refers to cannot be // borrowed as mutable // _some_string.push_str(", world!"); } fn change_mutable(some_string: &mut String) { some_string.push_str(", world"); } fn first_word(s: &String) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[..i]; } } &s[..] } // To make first_word work on either string literals (which are in fact string // slices, s.o.) one would write first_word like this… fn generic_first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[..i]; } } &s[..] }