mod string; mod fmt_debug; // when a String is passed to this function a move occurs: // BUT only the stack allocation (ptr, len, cap) is copied over // AND the underlying heap is preserved, without copy // // Why do we call it a "move"? // A move indicates ownership transfer, not data transfer fn takes_string(_s: String) { } fn takes_string_ref(_s: &String) { } // Compilation error and warning: // rustc: the size for values of type `str` cannot be known at compilation time // the trait `Sized` is not implemented for `str` [E0277] // rustc: function arguments must have a statically known size, // borrowed types always have a known size: `&` [E0277] // // Ok, so rust is an unsized type, // and compiler requires sized types for function params at compile time // // Why is this a problem? // rust doesn't know how much space to allocate for the variable // // str inactuality is the raw (UTF-8) bytes, not a container // fn takes_str(s: str) { } // this is fine because now the variable is a fat pointer: pointer + length // it's the length aspect that makes us abot to work on the str fn takes_str_ref(_s: &str) { } // yeah, we can do this fn _get_static_str() -> &'static str { "hello" } fn main() { println!("Hello, world!"); fmt_debug::test_report(); let s = String::new(); // no heap allocation until we add characters (capacity > 0) // let s_r: str; // ERROR: size not known at compile time let _s_rr: &str; // allowed let _s_rrr: &String; // allowed takes_string_ref(&s); takes_string_ref(&s); // works because the string was not moved in first call let ss = String::from("1"); // one heap allocation! takes_string(ss); // move occurs here // takes_string(ss); // ERROR: use of moved value here // takes_string_ref(&ss); // ERROR: borrow of moved value here let sss = String::new(); // deref coersion: // because String implements the trait Deref takes_str_ref(&sss); // *sss dereferences the String into its underlying str takes_str_ref(&*sss); // same as this! takes_str_ref(sss.as_ref()); // and this! let s4 = String::from("string4"); //let s4_slice = s4[0..]; // again we hit no size problem at compile time let _s4_slice = &s4[0..]; // but this works, because the &str has the length! // literals // &'static str is held onto by &str: // that's the programs read-only binary let s_lit = "easy as pie, right?"; let _s_lit2 : &str = "easy as pie, right?"; // same, data not copied, we just point to it let _s5 = String::from("literal is copied to heap"); // data copied to heap let _s6 = String::from(s_lit); //underlying data copied to heap // todo: Cow }