【问题标题】:Generic higher-order function reference error泛型高阶函数引用错误
【发布时间】:2016-01-12 09:01:49
【问题描述】:

我整晚都在用头撞这个。我正在尝试实现to_hash_map 方法,以便我可以这样做:

struct Person {
    id: i32,
    first_name: &'static str,
}

fn main() {
    let brad = Person {
        id: 1,
        first_name: "brad",
    };
    let barb = Person {
        id: 2,
        first_name: "Barb",
    };
    let a = vec![brad, barb];
    let key_func = |i: &Person| -> i32 { i.id };
    let value_func = |i: &Person| -> &str { i.first_name };
    let map = a.iter().to_hash_map(key_func, value_func);
    println!("{:?}", map)
}

并希望得到 HashMap

{
 1: "brad",
 2: "barb"
}

这是我最好的尝试:

trait ToHashMap<T,K,V, FK, FV>
    where K:Hash,
          K:Eq,
          FK:Fn(&T)->K,
          FV:Fn(&T)->V {

    fn to_hash_map(&self, key_func: FK, value_func: FV) -> HashMap<K, V>;
}

impl<T, K, V, FK, FV, I> ToHashMap<T, K, V, FK, FV> for I
    where K: Hash,
          K: Eq,
          FK: Fn(&T) -> K,
          FV: Fn(&T) -> V,
          I: Iterator<Item = T>
{
    fn to_hash_map(&self, key_func: FK, value_func: FV) -> HashMap<K, V>{
        let mut hm: HashMap<K, V> = HashMap::new();
        loop {
            match self.next() {
                Some(x) => {
                    hm.insert(key_func(&x), value_func(&x));
                }
                None => break,
            }
        }
        hm
    }
}

但我得到了错误:

error: type mismatch: the type `[closure@src/main.rs:92:20: 92:48]` implements the trait `for<'r> core::ops::Fn<(&'r Person,)>`, but the trait `for<'r> core::ops::Fn<(&'r &Person,
)>` is required (expected &-ptr, found struct `Person`) [E0281]
src/main.rs:94     let map = a.iter().to_hash_map(key_func, value_func);

我觉得我很接近。任何帮助表示赞赏:)

【问题讨论】:

  • 如果您可以使用 play.rust-lang.org 发布 MVCE,那就太好了。你很接近,只是缺少一个独立的例子。
  • 我会将大部分类型参数从 trait 移动到 trait 方法。 T 需要保留在 trait 上,否则无法在 impl 中正确绑定 I,但其他类型参数与实现 trait 的类型无关,仅在调用期间有意义到to_hash_mapHere's the code, based on Matthieu M.'s answer.

标签: generics rust higher-order-functions


【解决方案1】:

你们确实很亲近。

您面临的第一个问题是iter() 产生&amp;Person 类型的Iterator::Item,因此您传递给闭包的&amp;x&amp;&amp;Person 类型。

您可以更改闭包的类型以采用&amp;&amp;Person,或者使用into_iter 使用向量a

我遇到的另一个小问题是你不能通过不可变引用来获取迭代器:你需要修改迭代器进行迭代。按值取迭代器更简单。

总而言之,通过这两个调整我们可以得到(消耗向量):

trait ToHashMap<T, K, V, FK, FV>
    where K: Hash,
          K: Eq,
          FK: Fn(&T)->K,
          FV: Fn(&T)->V {

    fn to_hash_map(self, key_func: FK, value_func: FV) -> HashMap<K, V>;
}

impl<T, K, V, FK, FV, I> ToHashMap<T, K, V, FK, FV> for I
    where K: Hash,
          K: Eq,
          FK: Fn(&T) -> K,
          FV: Fn(&T) -> V,
          I: Iterator<Item = T>
{
    fn to_hash_map(self, key_func: FK, value_func: FV) -> HashMap<K, V> {
        let mut hm: HashMap<K, V> = HashMap::new();
        for x in self {
            hm.insert(key_func(&x), value_func(&x));
        }
        hm
    }
}

然后it compiles and runs 并产生:

{2: "Barb", 1: "brad"}

正如预期的那样。

【讨论】:

  • 很好的答案!我从中学到了很多东西(我才刚刚开始我的 Rust 之旅)。
  • @SimonWhitehead:欢迎上火车,小心有人说这是一种令人上瘾的语言;)
  • 谢谢!当您看到答案时,这似乎很明显:)
【解决方案2】:

问题在于a.iter() 返回一个迭代器,其项目为&amp;PersonToHashMap impl 的特征边界要求键和值函数采用 &amp;T,其中 T = Item,所以 T = &amp;Person,因此函数参数是 &amp; &amp;Person,这与您的函数不匹配。

您必须以某种方式放宽界限,但恐怕我的 Rust 知识不足以确切说明如何。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 1970-01-01
    • 2020-08-30
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多