使用IntoIterator特征编写通用特征实现,但仅适用于不可变参考实现者

crh*_*ino 2 traits rust

我正在定义一个接受i: &I参数的特征.我想ifor循环中使用这个值.

例如:

struct Test;

trait Bar<I> {
    fn bar(&self, i: &I);
}

impl<T, I: IntoIterator<Item=T>> Bar<I> for Test {
    fn bar(&self, i: &I) {
        for x in i {
            println!("woo!");
        }
    }
}

fn main() {
    let vec = vec!(1, 2, 3);
    let test = Test;
    test.bar(&vec);
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

这会导致错误:

<anon>:10:9: 12:10 error: the trait `core::iter::Iterator` is not implemented for the type `&I` [E0277] <anon>:10         for x in i { <anon>:11             println!("woo!"); <anon>:12         } <anon>:10:9: 12:10 help: see the detailed explanation for E0277 <anon>:10:9: 12:10 note: `&I` is not an iterator; maybe try calling `.iter()` or a similar method <anon>:10:9: 12:10 note: required by `core::iter::IntoIterator::into_iter` error: aborting due to previous error playpen: application terminated with error code 101
Run Code Online (Sandbox Code Playgroud)

我正在玩这个Deref特性,看看我是否可以得到一些工作,但无济于事.

我真的希望在函数定义中保留不可变引用,因为这个特性试图在许多类型上是通用的,并且定义其他实现使用Bar<&'a I>导致了一些其他与生命周期相关的问题,我也一直遇到问题.

huo*_*uon 7

说这I是一个IntoIterator没有说什么&I,例如x..y是一个IntoIterator(因为它是一个Iterator而且所有都是),但事实&(x..y)并非如此.

你特别想绑定&I,幸运的是可以通过一个where条款完成,例如

impl<I, T> Bar<I> for Test 
    where for<'a> &'a I: IntoIterator<Item = T>
{
    fn bar(&self, i: &I) {
        for x in i {
            println!("woo!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

for<'a>意味着"任何一生'a",因此该where条款&I总是说IntoIterator(只是写作where &I: IntoIterator还不够).

关于那里的T参数有一些选择,例如

  1. IntoIterator<Item = T>
  2. IntoIterator<Item = &'a T>
  3. 完全删除参数,然后写 IntoIterator

最好的选择取决于你正在做什么.对于问题中的具体示例,我将使用3,因为Item类型根本不重要.数字2是有意义的,因为几乎所有具有&T实现的类型都IntoIterator将产生引用(它似乎也避免了编译器目前在推断生命周期中的通用量化的推理中遇到的大部分错误/一般困难,其中命中1和3).