首页 > 解决方案 > 返回实现多个特征的对象 - 装饰器模式

问题描述

我目前正在 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). 实现该方法的常用方法是什么?有什么可以改进的?

澄清一下:我想 return 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 实现的装饰对象。方法加载和扫描都应该可用。

标签: rustdecoratortraitsdecltype

解决方案


一个函数只能返回一种类型的值,所以你的函数返回的类型不能依赖于运行时条件。但是,该类型可能是盒装特征,在这种情况下,存储在框中的值的类型可能会改变,只要它实现了适当的特征(或特征)。

从您提供的示例代码中,我认为这Lexer应该是一个类似的特征trait Lexer: Scan + Load {}(或者可能根本不需要存在Scanand特征,并且可以直接在中定义and方法)。那么你的函数应该只返回一个 boxed :LoadscanloadLexerbuildLexer

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 { … })
    }
}

推荐阅读