返回实现多个特征的对象-装饰器模式

时间:2019-04-30 03:12:19

标签: rust decorator traits decltype

我目前正在Rust中实现装饰器模式。 在Scala中,我们可以通过以下特性实现方法链接:

new Scanner
    with Whitespaces
    with Keywords

我想在Rust中做同样的事情。因此,扫描仪的不同特征:

pub struct Lexer();

pub trait Scan {
    fn scan(&self, start: &String) -> DomainTags;
}

pub struct Keywords<T> {
    decorated: T
}
impl<T: Scan> Scan for Keywords<T> {
    fn scan(&self, start: &String) -> DomainTags {
        ...
    }
}

pub struct Whitespaces<T> {
    decorated: T
}
impl<T: Scan> Scan for Whitespaces<T> {
    fn scan(&self, start: &String) -> DomainTags {
        ...
    }
}

但是由于我要使用以下方法构建词法分析器:

pub fn build() -> ??? {
    let lex = Lexer();
    let lex = Keyword {
        decorated: Whitespaces {
            decorated: lex
        }
    };
    lex
}

我不知道是否可以静态推断出返回类型为decltype(lex)之类的东西。实施该方法的通用方法是什么?有什么可以改善的?

要澄清:我想返回decltype(lex),因为单个Lexer也可能具有多个特征,例如:

pub trait Load {
    fn load<T : Load>(&self, keywords: &String);
}

impl Load for Lexer {
    fn load<Lexer>(&self, keyword : &String) {
       ...
    }
}

我希望也返回一个带有Load trait实现的修饰对象。方法加载和扫描都应该可用。

1 个答案:

答案 0 :(得分:1)

函数只能返回一种类型的值,因此函数返回的 type 不能取决于运行时条件。但是,该类型可能是装箱的特征,在这种情况下,只要实现适当的一个或多个特征,存储在框中的值的类型就可以更改。

从您提供的示例代码中,我认为Lexer应该是trait Lexer: Scan + Load {}这样的特征(或者也许ScanLoad特征不需要完全存在,scanload方法可以直接在Lexer中定义)。然后,您的build函数应该只返回一个带框的Lexer

pub trait Lexer {
    fn scan (&self, start: &String) -> DomainTags;
    fn load (&self, keyword : &String);
}

pub struct Keywords<T> {
    decorated: T
}
impl<T: Lexer> Lexer for Keywords<T> {
    …
}

pub struct Whitespaces<T> {
    decorated: T
}
impl<T: Lexer> Lexer for Whitespaces<T> {
    …
}

pub fn build (cond: bool) -> Box<dyn Lexer> {
    if cond {
        Box::new (Whitespaces { … })
    } else {
        Box::new (Keywords { … })
    }
}