rust - Weird macro behavior for type inference -
i'm trying understand macros & utilizing simple macro create hashmap similar vec!. reason if convert string &str inside macro doesn't seem work.
macro_rules! hashmap {     ($( $key: expr => $val: expr ),*) => {{          let mut map = ::std::collections::hashmap::new();          $( map.insert($key.clone(), $val.clone()); )*          map     }} }  fn works(){     let value1 = 5;     let value1str: &str = &value1.to_string();     let h = hashmap!["key0"   => "value0"                      , "key1" => value1str];     println!("{:?}", h); }  // fn does_not_work(){ //     let value1 = 5; //     let h = hashmap!["key0"   => "value0" //                      , "key1" => &value1.to_string()]; //     println!("{:?}", h); // }  fn main(){     works();     //does_not_work(); }        
this effective body of works() function:
fn works(){     let value1 = 5;     let value1str: &str = &value1.to_string();     let h = {         let mut map = hashmap::new();         map.insert("key0".clone(), "value0".clone());         map.insert("key1".clone(), value1str.clone());         map     };     println!("{:?}", h); }   and 1 of does_not_work():
fn does_not_work(){     let value1 = 5;     let h = {         let mut map = hashmap::new();         map.insert("key0".clone(), "value0".clone());         map.insert("key1".clone(), (&value1.to_string()).clone());         map     };     println!("{:?}", h); }   when clone() called on &str, simple byte-wise copy of fat pointer (two pointer-sized numbers): shared references copy; cloned reference has same lifetime original one, naturally. okay in works() because 3 of string slices used there point static memory string literals, , fourth 1 points temporary local variable lives until end of function:
let value1str: &str = &value1.to_string(); // in fact equivalent let temporary = value1.to_string(); let value1str: &str = &temporary;   because temporary lives longer hash map, reference can stored inside hash map: map gets destroyed first , never gets chance hold dangling reference.
in second case, however, clone() called on value of type &string, because &s if s: string give &str if compiler knows &str should target type, , not case because &value1.to_string() passed clone() afterwards. when clone() called on &string, naturally delegates impl clone string makes owned copy of string, giving string. in turn gives type mismatch error:
<anon>:20:34: 4:50 error: mismatched types:  expected `&str`,     found `collections::string::string` (expected &-ptr,     found struct `collections::string::string`) [e0308]   there way work around - can ask &str out of &string directly, e.g. explicit reborrowing:
&*value1.to_string()   however, problem arise. whatever temporary value value1.to_string() returns valid during expression inside used:
map.insert("key1".clone(), (&*value1.to_string()).clone()); // equivalent {     let temporary = value1.to_string();     map.insert("key1".clone(), (&*temporary).clone()); }  // these braces important!   you can see temporary destroyed when call insert() completes, , inserted reference become dangling. rust prevents compiler error.
Comments
Post a Comment