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(); } 

example on playpen

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

Popular posts from this blog

php - Invalid Cofiguration - yii\base\InvalidConfigException - Yii2 -

How to show in django cms breadcrumbs full path? -

ruby on rails - npm error: tunneling socket could not be established, cause=connect ETIMEDOUT -