定义一个通用函数,它将接受对实现特定特征的任何可迭代事物的借用

问题描述 投票:0回答:1

我有一个特质和一个实现该特质的东西:

trait HasPosition2D {
    fn x(&self) -> &i32;
    fn y(&self) -> &i32;
    fn x_mut(&mut self) -> &mut i32;
    fn y_mut(&mut self) -> &mut i32;
}

impl HasPosition2D for (i32,i32) {
    fn x(&self) -> &i32 {&self.0}
    fn y(&self) -> &i32 {&self.1}
    fn x_mut(&mut self) -> &mut i32 {&mut self.0}
    fn y_mut(&mut self) -> &mut i32 {&mut self.1}
}

我现在可以定义接受任何实现 HasPosition2D 的通用函数。例如

fn print(p: &impl HasPosition2D) {
    println!("{} {}", p.x(), p.y());
}

我还定义了一个函数,它接受任何可以转换为 HasPosition2D 迭代的东西。即

fn print_all(ps: impl IntoIterator<Item=impl HasPosition2D>) {
    for p in ps {
        println!("{} {}", p.x(), p.y());
    }
}

这允许我交换容器类型而无需更改代码。例如

let ps = vec![(42,42), (42,42)];
print_all(ps);
let ps = [(42,42), (42,42)];
print_all(ps);

不过,上面的函数移动了容器,我反而想借用。例如

//does not complile
fn print_all2(ps: &impl IntoIterator<Item=impl HasPosition2D>) {
    for p in ps {
        println!("{} {}", p.x(), p.y());
    }
}

但这给出了错误:

error[E0277]: `&impl IntoIterator<Item = impl HasPosition2D>` is not an iterator
  --> src\main.rs:35:14
   |
35 |     for p in ps {
   |              ^^ `&impl IntoIterator<Item = impl HasPosition2D>` is not an iterator
   |
   = help: the trait `Iterator` is not implemented for `&impl IntoIterator<Item = impl HasPosition2D>`
   = help: the trait `Iterator` is implemented for `&mut I`
   = note: required because of the requirements on the impl of `IntoIterator` for `&impl IntoIterator<Item = impl HasPosition2D>`

我还想定义一个类似的函数来接受可变借用。

最后,如何为每个 impl 特征创建类型别名? (使用

#![feature(type_alias_impl_trait)]
和/或
#![feature(trait_alias)] 

例如,对于非借用版本:

type HasPosition2DList = impl IntoIterator<Item=impl HasPosition2D>;

//does not compile
trait HasPosition2DList = IntoIterator<Item=impl HasPosition2D>;

我该怎么做?

generics rust traits
1个回答
1
投票

into_iter
按值(而不是引用)获取
self
,因此如果您想避免移动,那么这并不能解决您的问题。
Vec
可以
deref
进入切片,所以我认为你想要更多类似这样的东西,以便接受任一类型作为参数:

fn print_all(ps: &[impl HasPosition2D]) {
    for p in ps {
        println!("{} {}", p.x(), p.y());
    }
}

然后您可以按照示例中所示的方式调用它,只需添加

&
来借用:

fn main() {
    let ps = vec![(42,42), (42,42)];
    print_all(&ps);

    let ps = [(42,42), (42,42)];
    print_all(&ps);
}
© www.soinside.com 2019 - 2024. All rights reserved.