【发布时间】:2018-06-17 05:25:08
【问题描述】:
我有一个 trait 方法,它通过线性扫描集合中的元素来找到对集合中元素的引用。
我希望能够为 Vec<Tag> 和 &'a [Tag] 实现一次(并且理想情况下也支持其他可迭代的数据结构)。
在下面的代码中,TagFinder 的实例对于 Vec<Tag> 和 &'a [Tag] 的实现是相同的,但我找不到通用的表达方式。有可能吗?
这个other question 似乎是相关的,但我在这里有一个额外的间接级别,因为我正在处理“iterables”而不是迭代器。
相关地,如果有像IntoIterator 这样的特征暴露引用的迭代器(即Vec<T> 和&[T] 都将迭代&T,而不是Vec<T> 暴露一个拥有迭代器)。我不知道为什么这样的东西不存在。
struct Tag {
key: String,
value: String,
}
trait TagFinder {
fn find_tag(&self, key: &str) -> Option<&str>;
}
impl<'a> TagFinder for &'a [Tag] {
fn find_tag(&self, key: &str) -> Option<&str> {
find_tag(self.into_iter(), key)
}
}
impl TagFinder for Vec<Tag> {
fn find_tag(&self, key: &str) -> Option<&str> {
find_tag(self.into_iter(), key)
}
}
fn find_tag<'a, I>(tags: I, key: &str) -> Option<&'a str>
where
I: Iterator<Item = &'a Tag>,
{
tags.filter_map(|tag| match tag {
&Tag {
key: ref k,
value: ref v,
} if k == key =>
{
Some(v as &str)
}
_ => None,
}).next()
}
fn main() {
let v = vec![
Tag {
key: "a".to_owned(),
value: "1".to_owned(),
},
Tag {
key: "b".to_owned(),
value: "2".to_owned(),
},
];
let s: &[Tag] = &v;
assert!(v.find_tag("b") == Some("2"));
assert!(s.find_tag("b") == Some("2"));
}
编辑
在玩了一些之后,我想出了以下内容。它有效,但我对 为什么 它有效。
特征现在消耗
self,这根本不是可取的,除了IntoIterator<Item = &'a Tag>的唯一实现者似乎是借用类型,所以被销毁的self只是一个参考。我有点担心,因为没有什么(除了约定)阻止某人为Vec这样的拥有类型实现它。将生命周期参数从方法(省略)移动到特征很奇怪。我发现很难理解返回值如何以合理的生命周期结束。
为什么
v.find_tag(...)有效?这里的接收者是Vec,而不是参考。 Rust 如何将其转换为引用?
谢谢。 :)
trait TagFinder<'a> {
fn find_tag(self, key: &str) -> Option<&'a str>;
}
impl<'a, T> TagFinder<'a> for T
where
T: IntoIterator<Item = &'a Tag>,
{
fn find_tag(self, key: &str) -> Option<&'a str> {
find_tag(self.into_iter(), key)
}
}
【问题讨论】:
-
T: IntoIterator<Item=&Tag>?你可能不得不摆弄生命周期。 -
@SebastianRedl 我之前尝试过,但你激励我回到它。查看我的编辑。
-
你应该把你的编辑作为答案
-
@Boiethios 我有点希望有人能给出更好的答案,或者至少对这些观点发表评论。
标签: generics vector iterator rust slice