如何使用 static/dynamic dispatch 实现 iter 方法?

How to implement iter method using static/dynamic dispatch?

我需要实现方法 iter,它 return 是实现特征 Iterator<Item = char> 的东西。但是 return 值将是不同的实现,具体取决于枚举变体。

像这样:

pub enum Class {
    SingleChar(char),
    Range(Range),
    And(Vec<Class>),
    Or(Vec<Class>),
}

impl Class {
    pub fn iter(&self) -> Iterator<Item = char> {
        match *self {
            Class::SingleChar(c) => vec![c],
            Class::Range(ref range) => range.iter(),
            Class::And(ref classes) => {
                let iter: Option<_> = classes.iter().fold(None, |iter, &class| {
                    match iter {
                        None => Some(class.iter()),
                        Some(iter) => Some(iter.merge(class.iter())),
                    }
                });
                Box::new(iter.unwrap())
            },
            Class::Or(ref classes) => {
                let iter: Option<_> = classes.iter().fold(None, |iter, &class| {
                    match iter {
                        None => Some(class.iter()),
                        Some(iter) => Some(iter.interleave(class.iter())),
                    }
                });
                Box::new(iter.unwrap())
            },
        }
    }
}

range.iter() return 是一个实现 Iterator<Item=char>.

的结构

mergeinterleaveitertools方法,分别是returnMergeAscendInterleave(它们都实现了Iterator<Item=char>)

  1. 如何使用静态调度实现这样的方案?
  2. 如果静态调度不可行,如何使用动态调度实现这样的方案?

无法使用静态分派来完成。在未装箱的抽象 return 类型上有一个 tracking RFC issue,但 Rust 还没有(我不确定它是否可以涵盖 returning 不同类型的用例)。因此,动态调度是可行的方法。

实际上,你已经很接近了。只需让 return 键入 Box<Iterator<Item=char>> 并添加更多装箱:

pub fn iter(&self) -> Box<Iterator<Item=char>> {
    match *self {
        Class::SingleChar(c) => Box::new(Some(c).into_iter()),
        Class::Range(ref range) => Box::new(range.iter()),
        Class::And(ref classes) => {
            let iter: Option<_> = classes.iter().fold(None, |iter, &class| {
                match iter {
                    None => Some(Box::new(class.iter())),
                    Some(iter) => Some(Box::new(iter.merge(class.iter()))),
                }
            });
            iter.unwrap()
        },
        Class::Or(ref classes) => {
            let iter: Option<_> = classes.iter().fold(None, |iter, &class| {
                match iter {
                    None => Some(Box::new(class.iter())),
                    Some(iter) => Some(Box::new(iter.interleave(class.iter()))),
                }
            });
            iter.unwrap()
        },
    }
}

这应该有效。