【问题标题】:How do I return a Filter iterator from a function?如何从函数返回过滤器迭代器?
【发布时间】:2015-02-23 03:55:25
【问题描述】:

我想要这样的东西:

fn filter_one<'a, T: Int>(input: &'a Vec<T>) -> ??? {
    input.iter().filter(|&x| x == Int::one())
}

该函数的返回类型是什么? (我想返回迭代器)

(我希望这不是太明显,我已经尝试了半个小时,现在开始感到沮丧:p)

编辑:

我尝试按照here => playpen link 的指示进行操作

编译器给了我以下错误:

<anon>:5:1: 7:2 error: the trait `core::kinds::Sized` is not implemented for the type `for<'r> core::ops::Fn(&'r T) -> bool + 'a`
<anon>:5 fn filter_one<'a, T: Int>(input: &'a Vec<T>) -> Filter<&T, Iter<'a, T>, Fn(&T) -> bool>{
<anon>:6     input.iter().filter(|&x| x == Int::one())
<anon>:7 }
<anon>:5:1: 7:2 note: required by `core::iter::Filter`
<anon>:5 fn filter_one<'a, T: Int>(input: &'a Vec<T>) -> Filter<&T, Iter<'a, T>, Fn(&T) -> bool>{
<anon>:6     input.iter().filter(|&x| x == Int::one())
<anon>:7 }
<anon>:5:1: 7:2 error: the trait `for<'r> core::ops::Fn(&'r &'a T) -> bool` is not implemented for the type `for<'r> core::ops::Fn(&'r T) -> bool + 'a`
<anon>:5 fn filter_one<'a, T: Int>(input: &'a Vec<T>) -> Filter<&T, Iter<'a, T>, Fn(&T) -> bool>{
<anon>:6     input.iter().filter(|&x| x == Int::one())
<anon>:7 }
<anon>:5:1: 7:2 note: required by `core::iter::Filter`
<anon>:5 fn filter_one<'a, T: Int>(input: &'a Vec<T>) -> Filter<&T, Iter<'a, T>, Fn(&T) -> bool>{
<anon>:6     input.iter().filter(|&x| x == Int::one())
<anon>:7 }
error: aborting due to 2 previous errors
playpen: application terminated with error code 101

我如何告诉rustc Fn(&amp;T) -&gt; boolSized?

【问题讨论】:

标签: generics iterator rust


【解决方案1】:

锈 1.26

fn filter_one(input: &[u8]) -> impl Iterator<Item = &u8> {
    input.iter().filter(|&&x| x == 1)
}

fn main() {
    let nums = vec![1, 2, 3, 1, 2, 3];
    let other: Vec<_> = filter_one(&nums).collect();
    println!("{:?}", other);
}

锈 1.0

fn filter_one<'a>(input: &'a [u8]) -> Box<Iterator<Item = &'a u8> + 'a> {
    Box::new(input.iter().filter(|&&x| x == 1))
}

fn main() {
    let nums = vec![1, 2, 3, 1, 2, 3];
    let other: Vec<_> = filter_one(&nums).collect();
    println!("{:?}", other);
}

此解决方案需要额外分配。我们创建一个盒装特征对象。在这里,对象的大小始终是已知的(它只是一个或两个指针),但不需要知道堆中对象的大小。

作为Vladimir Matveev points out,如果您的谓词逻辑不需要来自环境的任何信息,您可以使用函数而不是闭包:

use std::{iter::Filter, slice::Iter};

fn filter_one<'a>(input: &'a [u8]) -> Filter<Iter<u8>, fn(&&u8) -> bool> {
    fn is_one(a: &&u8) -> bool {
        **a == 1
    }

    input.iter().filter(is_one)
}

fn main() {
    let nums = vec![1, 2, 3, 1, 2, 3];
    let other: Vec<_> = filter_one(&nums).collect();
    println!("{:?}", other);
}

另见:

【讨论】:

  • 谢谢!!在 rust 获得将泛型表示为 fn 返回类型的能力之前,我将暂时使用此解决方法!
  • 我很确定在这种情况下,在结构上显式实现闭包特征是一种矫枉过正。常规函数也实现了所有相关的特征,您不需要定义自定义结构并自己实现这些特征。此外,一旦您开始使用稳定的 Rust 版本,这将中断(因为它们不允许门控功能,并且未装箱的闭包特征的自定义实现将保持门控)。
  • 当然,如果您确实需要闭包来捕获其环境,那么这是目前唯一的选择...
  • 如果impltrait定义里面的函数呢?
  • @DrSensor 您自己尝试过吗?您可以从类型的固有方法中返回 impl Trait。你cannot use it with a trait
【解决方案2】:

不幸的是,不可能返回依赖于闭包的迭代器(特别是闭包,函数可以正常工作;见下文),就像 filter()map() 适配器返回的那些。原因如下。

这是filter()迭代器扩展方法的签名:

fn filter<P>(self, predicate: P) -> Filter<A, Self, P> where P: FnMut(&A) -> bool

请注意,闭包参数接受任何实现 FnMut 特征的类型。没错,即使不是全部,大多数标准库最近都已切换为使用未装箱的闭包,而不是旧的装箱闭包。

然而,这个签名意味着,如果你指定一个 closure 作为filter() 的参数,就像你在filter_one() 中所做的那样:

input.iter().filter(|&x| x == Int::one())

那么在这个特定调用P 的单态化之后将变成编译器生成的一些匿名未命名类型。因为它是未命名的,自然你不能在类型签名中指定它,因此,你也不能指定依赖于未装箱闭包的迭代器的类型 - 你只是不知道要写什么作为Filter&lt;A, I, P&gt; 的第三个参数。

您可以通过使用函数而不是闭包来解决此问题,这对于您的用例来说应该足够了:

use std::slice::Items;
use std::iter::Filter;
use std::num::Int;

fn filter_one<T: Int>(input: &[T]) -> Filter<&T, Items<T>, fn(&&T) -> bool> {
    fn equal_to_one<U: Int>(&&x: &&U) -> bool { x == Int::one() }
    input.iter().filter(equal_to_one::<T>)
}

fn main() {
    let v = [1i, 2, 3];
    let r: Vec<int> = filter_one(v.as_slice()).map(|x| *x).collect();
    println!("{}", r);
}

请注意,我还将&amp;Vec&lt;T&gt; 更改为&amp;[T] - 你永远不应该使用&amp;Vec&lt;T&gt;,因为它会不必要地限制你代码的灵活性。

然而,对于更一般的闭包情况,如果没有抽象返回类型,就不可能做到这一点。有提议添加它们,但被推迟到 1.0 之后。

【讨论】:

  • 非常感谢您的详细解释,我明白了这个问题! :)
  • 感谢您的回答。 Box&lt;Iterator&gt; 对这种情况有任何帮助吗?还是在关闭的情况下没有帮助?
  • 是的,Box&lt;Iterator&gt; 也可以提供帮助。事实上,trait 对象目前是返回闭包的一般问题的 解决方案。您可以在 Shepmaster 的回答中看到它是如何完成的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-14
  • 2016-07-22
  • 2022-10-02
  • 1970-01-01
相关资源
最近更新 更多