在Rust中堆叠迭代器的策略

时间:2018-07-06 17:43:39

标签: iterator rust

我正在尝试找出惯用的堆叠迭代器的方式。我正在尝试使用Vec个可以应用于迭代器的过滤器。

我首先尝试使用的是特征对象Vec,但是当我尝试将它们存储在配置结构中时,编译器告诉我,由于的通用类型参数,我的特征不是对象安全的我为特征定义的filter函数。

fn main() {
    let domains = vec!["hello.com".to_owned(), "h.com".to_owned()];
    let domain_filters = vec![DomainNameLength(5)];
    let config = SearchConfig { domain_filters };
    let filtered = config.filter_domains(domains);
    println!("{:#?}", filtered);
}

struct SearchConfig {
    domain_filters: Vec<Box<DomainNameFilter>>,
}

impl SearchConfig {
    fn filter_domains(&self, domains: Vec<String>) -> Vec<String> {
        filter_domains(self.domain_filters, domains)
    }
}

fn filter_domains(filters: Vec<impl DomainNameFilter>, domains: Vec<String>) -> Vec<String> {
    let mut filtered: Box<Iterator<Item = String>> = Box::new(domains.into_iter());
    for f in filters {
        filtered = f.filter(filtered);
    }
    filtered.collect()
}

trait DomainNameFilter {
    fn filter<'a>(
        &self,
        iter: impl IntoIterator<Item = String> + 'a,
    ) -> Box<Iterator<Item = String> + 'a>;
}

struct DomainNameLength(u8);
impl DomainNameFilter for DomainNameLength {
    fn filter<'a>(
        &self,
        iter: impl IntoIterator<Item = String> + 'a,
    ) -> Box<Iterator<Item = String> + 'a> {
        let max = self.0;
        Box::new(iter.into_iter().filter(move |x| x.len() as u8 <= max))
    }
}

Playground

error[E0038]: the trait `DomainNameFilter` cannot be made into an object
  --> src/main.rs:10:5
   |
10 |     domain_filters: Vec<Box<DomainNameFilter>>,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `DomainNameFilter` cannot be made into an object
   |
   = note: method `filter` has generic type parameters

我的第二个要解决的问题是一个Vec枚举,将调度编码为match语句。这对我来说似乎比较干净,但是我觉得我缺少一个更好的策略。

fn main() {
    let domains = vec!["hello.com".to_owned(), "h.com".to_owned()];
    let domain_filters = vec![DomainFilter::Length(5)];
    let config = SearchConfig { domain_filters };
    let filtered = config.filter_domains(domains);
    println!("{:#?}", filtered);
}

struct SearchConfig {
    domain_filters: Vec<DomainFilter>,
}

impl SearchConfig {
    fn filter_domains(&self, domains: Vec<String>) -> Vec<String> {
        filter_domains(&self.domain_filters, domains)
    }
}

pub enum DomainFilter {
    Length(u8),
}

impl DomainFilter {
    fn filter<'a>(
        &self,
        iter: impl Iterator<Item = String> + 'a,
    ) -> impl Iterator<Item = String> + 'a {
        match self {
            DomainFilter::Length(max) => {
                let m = *max;
                iter.filter(move |name| name.len() as u8 <= m)
            }
        }
    }
}

pub fn filter_domains(filters: &[DomainFilter], domains: Vec<String>) -> Vec<String> {
    let mut filtered: Box<Iterator<Item = String>> = Box::new(domains.into_iter());
    for f in filters {
        filtered = Box::new(f.filter(filtered));
    }
    filtered.collect()
}

Playground

我一直在文档中寻找一种构成迭代器的机制,似乎对此没有任何支持。我正在尝试执行以下操作。

let domains = vec!["hello.com"];
let filtered = compose(vec![DomainFilter::Length(5)]).filter(domains);

this question的主要区别在于,我试图在第一个示例中存储Vec的非对象安全特征,这是不可能的。在另一个问题中,他们只需要保存下一个整数即可取模。

0 个答案:

没有答案