2

I have a hm1: HashMap<K, V> where K is a tuple (k1, 2, k3) and V is a tuple of 10 elements like (v1, v2, v3, /* ... */ v10).

I have a function which acts on that HashMap, so I pass it as a parameter:

fn do_something(hm1: HashMap<(&i64, &i64, &Option<i64>), (&i64, &i64, /* ... */ &i64)>) -> () {
    //Access k1, k2, k3 and v1 .. v10 and do something with it
}

I have a second HashMap hm2 where the only difference is an additional key element. hm2: HashMap<K, V> where K is a tuple (k1, k2, k3, k4) and V is again a tuple of 10 elements (v1, v2, v3, /* ... */ v10).

I would want to avoid copy pasting the same do_something() function with an adapted signature, because the logic inside is nearly the same. The difference is just that I have an additional k4 element in the tuple which I'd also access then if I have hm2.

Is there a way to generalize the HashMap<K, V> parameter so I could pass both HashMaps and act on them without duplicating my function?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Toni Kanoni
  • 2,265
  • 4
  • 23
  • 29
  • I'd use a trait that I'd implement for both the tuples. – Boiethios Mar 09 '20 at 10:47
  • 3
    This can be start point https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3cdd6fa9467b2ecfa636e1c8e9897c45 – Đorđe Zeljić Mar 09 '20 at 11:01
  • 1
    @Đorđe Zeljić thanks, I think I got it with help of your code! I am implementing methods in the trait to get to the tuple elems, otherwise I don't know how to get them? I hope that's the way to go? Like https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9797cbce7faea4eca26b58ce1b15b27e – Toni Kanoni Mar 09 '20 at 11:38
  • @ToniKanoni yes, that was the idea – Đorđe Zeljić Mar 09 '20 at 12:45
  • @ToniKanoni Are you sure you need all those references? It will be much simpler if you used `i64` and `Option` instead of `&i64` and `Option<&i64>`. – Peter Hall Mar 09 '20 at 16:38
  • @PeterHall Yes, I have no influence on the inputs, they're all refs – Toni Kanoni Mar 10 '20 at 08:37

1 Answers1

0

I would want to avoid copy pasting the same do_something() function with an adapted signature, because the logic inside is nearly the same.

Copying nearly identical code for different types is what Rust generics are designed for! If the values are the same type in both cases, and only the keys are different, you can abstract over the keys:

type Value<'a> = (&'a i64, &'a i64, /* ... */ &'a i64);

fn do_something<K>(hash_map: HashMap<K, Value<'_>>) {
    for value in hash_map.values() {
        // do something with the value
    }
}

Given that you know nothing about the keys inside the function, you can't do much with them. In particular, you can't destructure them to access individual elements of the key tuples.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • I am not sure how to implement this with Generics, what is the second argument "key" here? Inside the the do_something function I need to loop over the complete hashmap (for_each(|(k, v)| ... ) and use all the values. I did it now like this: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=23e4213a0c758408265b22b1492c91d8 Could you translate this into your generic solution? – Toni Kanoni Mar 10 '20 at 08:28
  • My mistake. I somehow misread your original code, and thought the function took a key as an argument. Fixed it now. – Peter Hall Mar 10 '20 at 10:24