diff --git a/src/main.rs b/src/main.rs index da20e99..dc54c20 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod string; mod fmt_debug; // when a String is passed to this function a move occurs: @@ -41,6 +42,7 @@ fn _get_static_str() -> &'static str { } fn main() { + println!("Hello, world!"); fmt_debug::test_report(); let s = String::new(); // no heap allocation until we add characters (capacity > 0) @@ -78,6 +80,4 @@ fn main() { let _s6 = String::from(s_lit); //underlying data copied to heap // todo: Cow - - println!("Hello, world!"); } diff --git a/src/string.rs b/src/string.rs new file mode 100644 index 0000000..45be15e --- /dev/null +++ b/src/string.rs @@ -0,0 +1,83 @@ + +// 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 +#[allow(dead_code)] +fn takes_string(_s: String) { + +} + +#[allow(dead_code)] +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 +#[allow(dead_code)] +fn takes_str_ref(_s: &str) { + +} + +// yeah, we can do this +fn _get_static_str() -> &'static str { + "hello" +} + +#[test] +fn test_string() { + 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 +} +