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

时间:2016-01-15 07:31:20

标签: rust traits

我正在定义一个带有i: &I参数的特征。我想在i循环中使用此for值。

例如:

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);
}

Playground link

这会导致错误:

<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

我正在玩Deref使用Bar<&'a I>这个特性,看看我是否可以获得一些工作,但无济于事。

我真的想在函数定义中保留不可变引用,因为这个特性试图在许多类型上是通用的,并且使用{{1}}定义其他实现导致了我有的其他一些与生命周期相关的问题也遇到了麻烦。

2 个答案:

答案 0 :(得分:7)

IIntoIterator并没有提及&I,例如x..yIntoIterator(因为它是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!");
        }
    }
}

for<'a>只是意味着“任何一生'a”,因此where条款表明&I始终是IntoIterator(只是写作) where &I: IntoIterator还不够。)

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

  1. IntoIterator<Item = T>
  2. IntoIterator<Item = &'a T>
  3. 完全删除参数,然后只需编写IntoIterator
  4. 最佳选择将取决于您正在使用它做什么。对于问题中的具体示例,我将使用3,因为Item类型根本不重要。数字2是有道理的,因为几乎所有具有&T实现IntoIterator的类型都会产生引用(它似乎也避免了编译器目前在生命周期中推理通用量化的大部分错误/一般困难,点击1和3)。

答案 1 :(得分:2)

在Rust by convention中,名称以into开头的方法按值获取参数并将其转换为另一个值,通常会重用原始值中的某些资源。 IntoIterator特征及其into_iter遵循该惯例。

您确定需要在特质中使用&I吗?您的代码与I一样正常。那是因为IntoIterator&Vec<T>的实现。这就是为什么人们可以写for x in &v vVec的原因。

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);
}

playground