简体   繁体   English

如何使用通用 rust 类型实现字典?

[英]How to implement a dictionary with generic rust types?

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:我一直在研究官方的 rust 书,在“闭包”一章中,有一个演示如何使用 rust 使用 structs 和 impl 来使用缓存,然后最后他们说我们在代码中添加了函数,其中一个开始使用字典以便我们可以拥有多个缓存,我很快就做到了,但后来它说:

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.当前 Cacher 实现的第二个问题是它只接受带有一个 u32 类型参数并返回 u32 的闭包。 We might want to cache the results of closures that take a string slice and return usize values, for example.例如,我们可能希望缓存采用字符串切片并返回 usize 值的闭包结果。 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.尝试允许 HashMap 接收通用值,如下所示。

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`

UPDATE更新

I also carried out the recommendations of an answer but now I don't know how to start the HashMap with the following code.我也执行了答案的建议,但现在我不知道如何使用以下代码启动 HashMap。

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.然后我尝试了很多不同的东西,但没有一个对我有用,我在谷歌搜索了一下,但没有找到我需要的东西,这就是为什么我来找你寻求帮助,知道如何实现代码。

PS: I really like rust, I understand why it is the most loved PS:我很喜欢rust,我明白为什么最喜欢

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 .告诉您HashMap<K,V>::get仅在 K 实现EqHash时存在。 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:但是您的value function 没有对 K 施加任何此类限制。(相反,您尝试将限制限制在Hash<K,K>上。只需在where子句中将它们添加到K就足够了:

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.但是,这不足以让您的代码编译,您在 value 中所做的事情需要 K 是Copy - 这也需要添加到where子句中的限制中。 Usually, you'd try to reduce that requirement, either by using Clone instead or returning a reference.通常,您会尝试通过使用Clone代替或返回引用来减少该要求。

Aside: You should probably make it a Cacher<T,K,V> and let T: Fn(K)->V if you want a more general solution.另外:如果您想要更通用的解决方案,您可能应该将其Cacher<T,K,V>并让T: Fn(K)->V

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM