generics - Merge two HashMaps in Rust -


so i'm bit stuck, trying merge 2 hashmaps.

it's easy inline:

fn inline() {     let mut first_context = hashmap::new();     first_context.insert("hello", "world");     let mut second_context = hashmap::new();     second_context.insert("hey", "there");      let mut new_context = hashmap::new();     (key, value) in first_context.iter() {         new_context.insert(*key, *value);     }     (key, value) in second_context.iter() {         new_context.insert(*key, *value);     }     println!("inline:\t\t{}", new_context);     println!("inline:\t\t{}\t{} [initial maps still usable]", first_context, second_context); } 

it's easy enough make function:

fn abstracted() {     fn merge<'a>(first_context: &hashmap<&'a str, &'a str>, second_context: &hashmap<&'a str, &'a str>) -> hashmap<&'a str, &'a str> {         let mut new_context = hashmap::new();         (key, value) in first_context.iter() {             new_context.insert(*key, *value);         }         (key, value) in second_context.iter() {             new_context.insert(*key, *value);         }         new_context     }      let mut first_context = hashmap::new();     first_context.insert("hello", "world");     let mut second_context = hashmap::new();     second_context.insert("hey", "there");      println!("abstracted:\t{}", merge(&first_context, &second_context));     println!("abstracted:\t{}\t{} [initial maps still usable]", first_context, second_context); } 

however, can't seem generic version work:

fn generic() {     fn merge<'a, k: hash + eq, v>(first_context: &hashmap<&'a k, &'a v>, second_context: &hashmap<&'a k, &'a v>) -> hashmap<&'a k, &'a v> {         let mut new_context = hashmap::new();         (key, value) in first_context.iter() {             new_context.insert(*key, *value);         }         (key, value) in second_context.iter() {             new_context.insert(*key, *value);         }         new_context     }      let mut first_context = hashmap::new();     first_context.insert("hello", "world");     let mut second_context = hashmap::new();     second_context.insert("hey", "there");      println!("generic:\t{}", merge(&first_context, &second_context));     println!("generic:\t{}\t{} [initial maps still usable]", first_context, second_context); } 

the above code on play.rust-lang.org.

compiling it:

error: trait `core::kinds::sized` not implemented type `str` 

i compiler confused size of generic value, i'm not sure why "str" doesn't have strict memory size? know string slice , not type, still should work, no? bug?

i thought relatively trivial function. if has solution, i'd love learn. ideally, i'd love see solution trait mergeable , write decorator hashmap<&k, &v>, such can call let new_context = first_context.merge(&second_context); can different question.

this version work:

use std::collections::hashmap; use std::hash::hash;  fn main() {     fn merge<k: hash + eq + copy, v: copy>(first_context: &hashmap<k, v>, second_context: &hashmap<k, v>) -> hashmap<k, v> {         let mut new_context = hashmap::new();         (key, value) in first_context.iter() {             new_context.insert(*key, *value);         }         (key, value) in second_context.iter() {             new_context.insert(*key, *value);         }         new_context     }      let mut first_context = hashmap::new();     first_context.insert("hello", "world");     let mut second_context = hashmap::new();     second_context.insert("hey", "there");      println!("generic:\t{}", merge(&first_context, &second_context));     println!("generic:\t{}\t{} [initial maps still usable]", first_context, second_context); } 

the difference in signature of merge(). here yours:

fn merge<'a, k: hash + eq, v>(first_context: &hashmap<&'a k, &'a v>, second_context: &hashmap<&'a k, &'a v>) -> hashmap<&'a k, &'a v> 

here mine:

fn merge<k: hash + eq + copy, v: copy>(first_context: &hashmap<k, v>, second_context: &hashmap<k, v>) -> hashmap<k, v> 

for reason trying abstract hashmap<&str, &str> hashmap<&k, &v>, not correct: while &str is borrowed pointer, special - points dynamically sized type str. size of str not known compiler, can use through pointer. consequently, neither hash nor eq implemented str, implemented &str instead. hence i've changed hashmap<&'a k, &'a v> hashmap<k, v>.

the second problem in general can't write function if takes references maps. non-generic merge function works because &str reference , references implicitly copyable. in general case, however, both keys , values can non-copyable, , merging them single map require moving these maps function. adding copy bound allows that.

you can add clone bound instead of copy , use explicit clone() call:

fn merge<k: hash + eq + clone, v: clone>(first_context: &hashmap<k, v>, second_context: &hashmap<k, v>) -> hashmap<k, v> {     // ...     (key, value) in first_context.iter() {         new_context.insert(key.clone(), value.clone());     }     // ... } 

the general way, however, moving maps function:

fn merge<k: hash + eq, v>(first_context: hashmap<k, v>, second_context: hashmap<k, v>) -> hashmap<k, v>  {     // ...     (key, value) in first_context.into_iter() {         new_context.insert(key, value);     }     // ... } 

note into_iter() method consumes map, returns iterator of tuples actual values instead of references.


Comments

Popular posts from this blog

ruby on rails - RuntimeError: Circular dependency detected while autoloading constant - ActiveAdmin.register Role -

c++ - OpenMP unpredictable overhead -

javascript - Wordpress slider, not displayed 100% width -