Возвращаемый объект, реализующий несколько признаков - образец декоратора - PullRequest
0 голосов
/ 30 апреля 2019

Я сейчас реализую шаблон декоратора в 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), потому что у меня также может быть несколько черт для одного Лексера, например:

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

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

И я надеюсь вернуть украшенный объект с реализацией черты Load. Оба метода загрузки и сканирования должны быть доступны.

1 Ответ

1 голос
/ 30 апреля 2019

Функция может возвращать только один тип значения, поэтому тип , возвращаемый вашей функцией, не может зависеть от условий выполнения. Однако этот тип может представлять собой черту в штучной упаковке, и в этом случае тип значения, сохраненного в ящике, может измениться, если он реализует соответствующую черту (или черты).

Исходя из предоставленного вами примера кода, я думаю, что Lexer должна быть такой чертой, как trait Lexer: Scan + Load {} (или, возможно, черты Scan и Load вообще не должны существовать, а * 1009) Методы * и load могут быть определены непосредственно в 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 { … })
    }
}
...