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