Reputation: 66
I have been studying the official rust book, in the chapter on "closures" there is a demonstration of how to use cache with rust using structs and impl, then at the end they say that we add functions to the code, one of them start to use a dictionary so that we can have a multiple cache, I did that quickly, but then it says:
The second problem with the current Cacher implementation is that it only accepts closures that take one parameter of type u32 and return a u32. We might want to cache the results of closures that take a string slice and return usize values, for example. To fix this issue, try introducing more generic parameters to increase the flexibility of the Cacher functionality.
the relevant part of the code right now, with my modifications it looks like this.
struct Cacher<T>
where
T: Fn(u32) -> u32,
{
calculation: T,
value: HashMap<u32, u32>,
}
impl<T> Cacher<T>
where
T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
value: HashMap::new(),
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value.get(&arg) {
Some(n) => *n,
None => {
let v = (self.calculation)(arg);
self.value.insert(arg, v);
v
},
}
}
}
try to allow the HashMap to receive generic values as follows.
struct Cacher<T, K>
where
T: Fn(K) -> K,
HashMap<K, K>: std::hash::Hash + std::cmp::Eq,
{
calculation: T,
value: HashMap<K, K>,
}
impl<T, K> Cacher<T, K>
where
T: Fn(K) -> K,
HashMap<K, K>: std::hash::Hash + std::cmp::Eq,
{
fn new(calculation: T) -> Cacher<T, K> {
Cacher {
calculation,
value: HashMap::new(),
}
}
fn value(&mut self, arg: K) -> K {
match self.value.get(&arg) {
Some(n) => *n,
None => {
let v = (self.calculation)(arg);
self.value.insert(arg, v);
v
},
}
}
}
I got the following error
error[E0599]: no method named `get` found for struct `HashMap<K, K>` in the current scope
--> src/main.rs:27:26
|
27 | match self.value.get(&arg) {
| ^^^ method not found in `HashMap<K, K>`
|
= note: the method `get` exists but the following trait bounds were not satisfied:
`K: Eq`
`K: Hash`
error[E0599]: no method named `insert` found for struct `HashMap<K, K>` in the current scope
--> src/main.rs:31:28
|
31 | self.value.insert(arg, v);
| ^^^^^^ method not found in `HashMap<K, K>`
|
= note: the method `insert` exists but the following trait bounds were not satisfied:
`K: Eq`
`K: Hash`
error[E0277]: the trait bound `HashMap<_, _>: Hash` is not satisfied
--> src/main.rs:39:33
|
5 | struct Cacher<T, K>
| ------ required by a bound in this
...
8 | HashMap<K, K>: std::hash::Hash + std::cmp::Eq,
| --------------- required by this bound in `Cacher`
...
39 | let mut expensive_closure = Cacher::new(|num| {
| ^^^^^^^^^^^ the trait `Hash` is not implemented for `HashMap<_, _>`
error[E0599]: no function or associated item named `new` found for struct `Cacher<_, _>` in the current scope
--> src/main.rs:39:41
|
5 | / struct Cacher<T, K>
6 | | where
7 | | T: Fn(K) -> K,
8 | | HashMap<K, K>: std::hash::Hash + std::cmp::Eq,
... |
11 | | value: HashMap<K, K>,
12 | | }
| |_- function or associated item `new` not found for this
...
39 | let mut expensive_closure = Cacher::new(|num| {
| ^^^ function or associated item not found in \`Cacher<_, _>\`
|
::: /home/fraco/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/collections/hash/map.rs:201:1
|
201 | pub struct HashMap<K, V, S = RandomState> {
| ----------------------------------------- doesn't satisfy `HashMap<_, _>: Hash`
|
= note: the method `new` exists but the following trait bounds were not satisfied:
`HashMap<_, _>: Hash`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `functionall`
I also carried out the recommendations of an answer but now I don't know how to start the HashMap with the following code.
struct Cacher<T, K>
where
T: Fn(K) -> K,
K: Hash + Eq,
{
calculation: T,
value: HashMap<K,K>,
}
impl<T, K> Cacher<T, K>
where
T: Fn(K) -> K,
K: Hash + Eq,
{
fn new(calculation: T) -> Cacher<T, K> {
Cacher {
calculation,
value: HashMap::new(),
}
}
error
error[E0308]: mismatched types
--> src/main.rs:24:20
|
16 | impl<T, K> Cacher<T, K>
| - this type parameter
...
24 | value: HashMap::new(),
| ^^^^^^^^^^^^^^ expected type parameter `K`, found struct `HashMap`
|
= note: expected type parameter `K`
found struct `HashMap<_, _>`
error[E0599]: no method named `get` found for type parameter `K` in the current scope
--> src/main.rs:29:26
|
29 | match self.value.get(&arg) {
| ^^^ method not found in `K`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `get`, perhaps you need to restrict type parameter `K` with it:
|
16 | impl<T, K: SliceIndex> Cacher<T, K>
| ^^^^^^^^^^^^^
error[E0599]: no method named `insert` found for type parameter `K` in the current scope
--> src/main.rs:33:28
|
33 | self.value.insert(arg, v);
| ^^^^^^ method not found in `K`
error: aborting due to 3 previous errors
Then I tried many different things and none of them worked for me, I searched a little in google but I did not find what I need, that's why I come to you to ask for help, to know how to implement what is asked in the code.
P.S: I really like rust, I understand why it is the most loved
Upvotes: 0
Views: 2075
Reputation: 73460
The error message
error[E0599]: no method named `get` found for struct `HashMap<K, K>` in the current scope
--> src/main.rs:27:26
|
27 | match self.value.get(&arg) {
| ^^^ method not found in `HashMap<K, K>`
|
= note: the method `get` exists but the following trait bounds were not satisfied:
`K: Eq`
`K: Hash`
tells you that HashMap<K,V>::get
only exists when K implements Eq
and Hash
.
but your value
function doesn't place any such restriction on K. (Instead you've tried to stick the restriction on Hash<K,K>
. It should be enough to just add them to K
in the where
clause:
impl<T, K> Cacher<T, K>
where
T: Fn(K) -> K,
K: std::hash::Hash + std::cmp::Eq
{
This won't be enough to get your code to compile though, what you are doing inside value requires K to be Copy
- which will also need to be added to the restrictions in the where
clause. Usually, you'd try to reduce that requirement, either by using Clone
instead or returning a reference.
Aside: You should probably make it a Cacher<T,K,V>
and let T: Fn(K)->V
if you want a more general solution.
Upvotes: 1