首页 > 解决方案 > 一个函数可以同时采用 IntoIterator和 IntoIterator<&T>?

问题描述

我想要一个带有两个参数的函数,这两个参数都可以变成Foo. 问题是我想接受既是IntoIterator<Foo>又是的东西IntoIterator<&Foo>。重要Foo的是Copy,我可以从它的参考中廉价地创建一个拥有的副本。

我目前的解决方案是:

use std::borrow::Cow;
use std::iter::IntoIterator;

fn main() {
    let foos = [Foo {}, Foo {}, Foo {}];
    let references = || foos.iter();
    let owned = || foos.iter().cloned();
    bar(references(), references());
    bar(references(), owned());
    bar(owned(), references());
    bar(owned(), owned());
}

#[derive(Copy, Clone)]
struct Foo {
    // code ommitted here
}

impl<'a> From<Foo> for Cow<'a, Foo> {
    fn from(foo: Foo) -> Self {
        Self::Owned(foo)
    }
}

impl<'a> From<&'a Foo> for Cow<'a, Foo> {
    fn from(foo: &'a Foo) -> Self {
        Self::Borrowed(foo)
    }
}

fn bar<'a, AIter, A, BIter, B>(alpha_iter: AIter, beta_iter: BIter)
  where 
    AIter: IntoIterator<Item=A>,
    A: Into<Cow<'a, Foo>>,
    BIter: IntoIterator<Item=B>,
    B: Into<Cow<'a, Foo>>
{
    for (alpha, beta) in alpha_iter.into_iter().zip(beta_iter.into_iter()) {
       some_foo_specific_thing(*alpha.into(), *beta.into());
    }
}

fn some_foo_specific_thing(alpha: Foo, beta: Foo) {
    // code ommitted here
}

操场

有没有办法在更少的行/没有的情况下做到这一点Cow

标签: rust

解决方案


首先,您不需要IntoIterator在这里完全绑定。刚好够用Iterator<Item = Foo>

use std::borrow::Cow;
use std::iter::IntoIterator;

fn main() {
    let foos = [Foo {}, Foo {}, Foo {}];
    let references = || foos.iter(); // it is iterator itself
    let owned = || foos.iter().cloned(); // it is iterator itself
    bar(references(), references());
    bar(references(), owned());
    bar(owned(), references());
    bar(owned(), owned());
}
fn bar<'a, AIter, A, BIter, B>(alpha_iter: AIter, beta_iter: BIter)
  where 
    AIter: Iterator<Item = A>,
    A: Into<Cow<'a, Foo>>,
    BIter: Iterator<Item = B>,
    B: Into<Cow<'a, Foo>>
{
    for (alpha, beta) in alpha_iter.zip(beta_iter) {
       some_foo_specific_thing(*alpha.into(), *beta.into());
    }
}

其次,我认为最好使用Borrowtrait:

fn bar<'a, AIter, A, BIter, B>(alpha_iter: AIter, beta_iter: BIter)
  where 
    AIter: Iterator<Item = A>,
    A: std::borrow::Borrow<Foo> + Copy,
    BIter: Iterator<Item = B>,
    B: std::borrow::Borrow<Foo> + Copy,
{
    let alpha_iter = alpha_iter.map(|item| *item.borrow()); // here we  get a reference to an item and then make a copy to own it
    let beta_iter = beta_iter.map(|item| *item.borrow()); // here we  get a reference to an item and then make a copy to own it
    
    for (alpha, beta) in alpha_iter.zip(beta_iter) {
       some_foo_specific_thing(alpha, beta);
    }
}

推荐阅读