【发布时间】:2019-03-13 17:51:36
【问题描述】:
我正在尝试为任何元素序列实现一个特征,以便它适用于向量、数组和切片。到目前为止,我已经尝试了几种方法,但我无法编译它们中的任何一种:(
我有这个 trait,一个使用它的函数,以及一个实现这个 trait 的基本数据类型:
trait Hitable {
fn hit(&self, val: f64) -> bool;
}
fn check_hit<T: Hitable>(world: &T) -> bool {
world.hit(1.0)
}
struct Obj(f64);
impl Hitable for Obj {
fn hit(&self, val: f64) -> bool {
self.0 > val
}
}
我希望能够为Obj 的序列实现该特征。
如果我将其限制为向量,它就可以正常工作:
impl<T> Hitable for Vec<T>
where
T: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.iter().any(|h| h.hit(val))
}
}
fn main() {
let v = vec![Obj(2.0), Obj(3.0)];
println!("{}", check_hit(&v));
}
但我想让它更通用,以便它适用于数组和切片;我该怎么做?
我尝试了以下四种尝试:
尝试 #1:用于 Hitables 上的迭代器。
// It's not clear how to call it:
// vec.iter().hit(...) does not compile
// vec.into_iter().hit(...) does not compile
//
impl<T, U> Hitable for T
where
T: Iterator<Item = U>,
U: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.any(|h| h.hit(val))
}
}
尝试#2:对于可以变成迭代器的东西。
// Does not compile as well:
//
// self.into_iter().any(|h| h.hit(val))
// ^^^^ cannot move out of borrowed content
//
impl<T, U> Hitable for T
where
T: IntoIterator<Item = U>,
U: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.into_iter().any(|h| h.hit(val))
}
}
尝试 #3:切片。
// This usage doesn't compile:
// let v = vec![Obj(2.0), Obj(3.0)];
// println!("{}", check_hit(&v));
//
// It says that Hitable is not implemented for vectors.
// When I convert vector to slice, i.e. &v[..], complains about
// unknown size in compilation time.
impl<T> Hitable for [T]
where
T: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.iter().any(|h| h.hit(val))
}
}
尝试 #4:迭代器 + 克隆
// let v = vec![Obj(2.0), Obj(3.0)];
// println!("{}", check_hit(&v.iter()));
//
// does not compile:
// println!("{}", check_hit(&v.iter()));
// ^^^^^^^^^ `&Obj` is not an iterator
//
impl<T, U> Hitable for T
where
T: Iterator<Item = U> + Clone,
U: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.clone().any(|h| h.hit(val))
}
}
【问题讨论】:
-
&self— 你知道 Rust 中的可变性概念,以及Iterator::next需要可变接收器这一事实吗? -
Hitable for T...&self— 你知道对类型的引用可能实现与类型本身不同的特征吗? -
@Shepmaster 是的,我想我理解这些概念。我的 trait 不需要改变底层价值,所以也许在迭代器上实现它不是一个好主意。关于您的第二点:当我为某些引用类型 &T 实现特征时,我不太确定特征的函数参数 &self 会发生什么。会是&&T吗?我应该取消引用它吗?我在 trait 函数中使用 &self 来表明我只需要读取权限(没有所有权,没有突变)......
-
Playground ,这里是 into_iter() 的工作版本。和迭代器()。正如@Shepmaster 指出的那样,它与可变性有关。
-
@ÖmerErden 是的,谢谢,它现在确实有效。然而,现在当我意识到为迭代器实现它需要突变时,我认为最好只在切片上实现它,因为 trait 函数不应该需要突变(它只是读取数据)。
标签: generics rust iterator traits