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

Writing a generic trait implementation with IntoIterator trait, but only for immutable reference implementors

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

例如:

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> 定义其他实现导致了一些其他与生命周期相关的问题我也遇到了麻烦。

IIntoIterator 并没有说明 &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!");
        }
    }
}

for<'a> 只是表示 "for any lifetime 'a",因此 where 子句表示 &I 始终是 IntoIterator(只需写 where &I: IntoIterator 还不够)。

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

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

最佳选择取决于您使用它做什么。对于问题中的具体示例,我会选择 3,因为 Item 类型根本不重要。数字 2 是有道理的,因为几乎所有具有 &T 实现 IntoIterator 的类型都会产生引用(它似乎也避免了编译器目前在推理生命周期内的通用量化方面遇到的大多数 bugs/general 困难, 命中 1 和 3).

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

您确定需要在您的特质中使用 &I 吗?您的代码在 I 下工作得很好。那是因为 &Vec<T> 有一个 IntoIterator 的实现。这就是为什么可以写 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