added more strings and todos
This commit is contained in:
+68
-32
@@ -1,3 +1,4 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
// when a String is passed to this function a move occurs:
|
||||
// BUT only the stack allocation (ptr, len, cap) is copied over
|
||||
@@ -10,6 +11,8 @@ fn takes_string(_s: String) {
|
||||
|
||||
}
|
||||
|
||||
// You can do this, but you probably want &str
|
||||
// UNLESS you want `&mut String`
|
||||
#[allow(dead_code)]
|
||||
fn takes_string_ref(_s: &String) {
|
||||
|
||||
@@ -27,7 +30,7 @@ fn takes_string_ref(_s: &String) {
|
||||
// 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
|
||||
// str in actuality 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
|
||||
@@ -42,42 +45,75 @@ fn _get_static_str() -> &'static str {
|
||||
"hello"
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string() {
|
||||
let s = String::new(); // no heap allocation until we add characters (capacity > 0)
|
||||
// The #[cfg(test)] annotation on the tests module tells Rust to compile
|
||||
// and run the test code only when you run cargo test, not when you run cargo build
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*; // need access to functions above
|
||||
|
||||
// let s_r: str; // ERROR: size not known at compile time
|
||||
let _s_rr: &str; // allowed
|
||||
let _s_rrr: &String; // allowed
|
||||
#[test]
|
||||
fn test_string() {
|
||||
let s = String::new(); // no heap allocation until we add characters (capacity > 0)
|
||||
|
||||
takes_string_ref(&s);
|
||||
takes_string_ref(&s); // works because the string was not moved in first call
|
||||
// let s_r: str; // ERROR: size not known at compile time
|
||||
let _s_rr: &str; // allowed
|
||||
let _s_rrr: &String; // allowed
|
||||
|
||||
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
|
||||
takes_string_ref(&s);
|
||||
takes_string_ref(&s); // works because the string was not moved in first call
|
||||
|
||||
let sss = String::new();
|
||||
// deref coersion:
|
||||
// because String implements the trait Deref<Target = str>
|
||||
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 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 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!
|
||||
let sss = String::new();
|
||||
// deref coersion:
|
||||
// because String implements the trait Deref<Target = str>
|
||||
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!
|
||||
|
||||
// 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
|
||||
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!
|
||||
|
||||
// todo: Cow
|
||||
// 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
|
||||
|
||||
// Box<str> is owned, heap allocated, fixed size, immutable
|
||||
// where as `&str` is borrowed view, linked to source, immutable
|
||||
// both have (ptr, len) -> underlying mem
|
||||
let _s7 : Box<str> = "hello".into();
|
||||
|
||||
// Rc<str> (single-threaded reference counting)
|
||||
// HEAP memory layout:
|
||||
// * counter (strong)
|
||||
// * counter (weak)
|
||||
// * len
|
||||
// * data
|
||||
// STACK memory:
|
||||
// * ptr
|
||||
// * len
|
||||
//
|
||||
// Why are there two lengths?
|
||||
let rc_str : Rc<str> = Rc::from("rc_str");
|
||||
// let rc_str2 : Rc<str> = rc_str; // this moves
|
||||
let rc_str2 : Rc<str> = rc_str.clone(); // copy ptr, increment counter
|
||||
println!("printing {}", rc_str);
|
||||
println!("printing {}", rc_str);
|
||||
println!("printing {}", rc_str2);
|
||||
|
||||
// todo: Arc<str>
|
||||
// todo: Cow
|
||||
// todo: byte strings: &[u8] and Vec<u8>
|
||||
// todo: Os & platform strings: OsStr & OsString, Path & PathBuf
|
||||
// todo: ffi strings: CString & CStr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user