【问题标题】:How do I return different iterators from a function? [duplicate]如何从函数返回不同的迭代器? [复制]
【发布时间】:2022-10-02 22:54:10
【问题描述】:

我正在尝试更改我在 rust 书中实现的 minigrep 应用程序,使其也像真正的 grep 一样采用 stdin 输入。

我创建了一个小型辅助函数,它接受配置并决定(当前根据环境变量)是返回缓冲的读取器迭代器还是标准输入迭代器:

fn stdinOrFile(cfg: &Cfg) -> impl Iterator<Item = String> + \'_ {
    if cfg.stdin {
        return io::stdin().lines();
    }
    
    let file = File::open(cfg.path.clone()).unwrap();
    let reader = BufReader::new(file);
    return reader.lines();
}

意识到我在黑暗中用棍子戳,看来返回特征对象的语法is legal,现在认为这是一个死胡同。编译器似乎仍在尝试推断返回值的具体类型,并抱怨另一种类型不是同一类型,但据我所知,它们都实现了迭代器特征。

我必须解决的一些想法:

  1. Box 返回前的值
  2. 创建一个通用包装器来包装这两种底层类型,然后,由于minigrep 匹配器只使用迭代器的filter 功能,我可以根据它的底层类型在包装器上分别实现filter持有,然后将调用基础类型的相关方法。

    有任何想法吗? 如果推断出具体实现,为什么返回类型中允许使用特征对象语法?

    标签: rust iterator


    【解决方案1】:

    你认为你应该装箱是对的。 impl Iterator 不是特征对象。它可能意味着几个不同的东西,但在返回位置它是一个特殊的impl return syntax。实际上,该函数仍然返回一个具体的、普通的已知类型的迭代器,只是编译器会为您推断出该类型。它最常与迭代器一起使用,因为编写 impl Iterator&lt;Item=u32&gt;实际的返回类型可以是诸如Map&lt;Vec::Iter&lt;String&gt;, fn(String) -&gt; i32&gt; 之类的恶作剧(在函数参数是闭包的情况下甚至可以是不可表示的)。

    但是,使用impl 返回时,必须仍然存在具体类型。您不能在两个不同的分支中返回两种不同的类型。所以在这种情况下,你需要一个特征对象。那是dyn Iterator,但dyn Iterator 没有大小,所以你需要将它包装在Box 中来处理它。

    Box<dyn Iterator<Item = String> + '_>
    

    当然,您需要将返回值包装在 Box::new 中,因为 Rust 不会为您这样做。

    【讨论】:

    • 好的。那成功了。非常感谢
    • 使用either(它也在itertools 中)也是一种选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-23
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    相关资源
    最近更新 更多