我有一个特征方法,通过线性扫描其元素来找到对集合中元素的引用。
我希望能够为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>
的唯一实施者似乎是借用类型这一事实外,这一点根本不可取,因此{{1}被破坏的只是一个参考。我有点小心,因为没有任何东西(除了惯例)阻止有人为self
这样的拥有类型实现这一点。
将life参数从方法(省略)移动到特征是很奇怪的。我发现很难理解返回值如何以合理的生命周期结束。
为什么Vec
有效?这里的接收者是v.find_tag(...)
而不是参考。 Rust如何将其转换为引用?
感谢。 :)
Vec
答案 0 :(得分:3)
如何为
的所有迭代实现一次特征&T
就像你指定的那样:
trait Foo {}
impl<'a, T: 'a, I> Foo for I
where
I: Iterator<Item = &'a T>,
{
}
如果您愿意,可以将IntoIterator
替换为Iterator
。
针对您的具体情况:
trait TagFinder<'a> {
fn find_tag(self, key: &str) -> Option<&'a str>;
}
impl<'a, I> TagFinder<'a> for I
where
I: IntoIterator<Item = &'a Tag>,
{
fn find_tag(self, key: &str) -> Option<&'a str> {
self.into_iter()
.filter(|tag| tag.key == key)
.map(|tag| tag.value.as_ref())
.next()
}
}
该特征现在消耗
self
,除了IntoIterator<Item = &'a Tag>
的唯一实施者似乎是借用类型这样的事实之外,这一点根本不可取,因此self
是Vec
被摧毁只是一个参考。我有点谨慎,因为没有任何东西(除了惯例)阻止有人为'a
这样的拥有类型实现这一点。
如果你能找到某种方式来获取拥有价值并返回它的参考,那么你就发现了Rust的内存安全性的一个关键漏洞。请参阅Is there any way to return a reference to a variable created in a function?。
将life参数从方法(省略)移动到特征是很奇怪的。我发现很难理解返回值如何以合理的生命周期结束。
我不明白这种困惑。您已明确指定了生命周期,因此以何种方式不合理?你没有从方法中删除它,你只是将它添加到特征中,因为现在特征必须知道v.find_tag(...)
来自&#34;外部&#34;特质本身。
为什么
Vec
有效?这里的接收者是_ = childViewController.view
而不是参考。 Rust如何将其转换为参考?
与调用值时引用的任何其他方法调用相同的方式。见What are Rust's exact auto-dereferencing rules?