为Rust中的traits提供类似继承的行为

Phi*_*hil 2 traits rust

所以,假设我有两个小特征,ParserTrigger.一个解析器需要串片,做了一些分析,并返回字符串的切片,而不消耗的令牌.出错时,会返回错误.一个触发就像一个分析器,但它不希望任何标记,因此做一些事情,也许返回一个错误.每个触发器都可以被视为解析器,我想定义使该规则成为现实的函数.这就是我的直觉让我做的事情:

pub trait Parser<'a> {
  fn parse(&mut self, &'a [String]) -> Result<&'a [String], Error>;
}

pub trait Trigger {
  fn pull(&mut self) -> Option<Error>;
}

impl<'a> Parser<'a> for Trigger {
  fn parse(&mut self, tokens: &'a [String]) -> Result<&'a [String], Error> {
    match self.pull() {
      Some(err) => Err(err),
      _         => Ok(tokens) //Returns the tokens untouched
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我收到此错误消息:

parsers.rs:37:33: 37:40 error: explicit lifetime bound required
parsers.rs:37 impl<'a> Parser<'a> for Trigger {
                                      ^~~~~~~
Run Code Online (Sandbox Code Playgroud)

你能否解释一下发生了什么以及实现我想要的东西的惯用方法.谢谢 :)

Vla*_*eev 6

Rust中的特征不是常规类型.它们既可以用作泛型边界,也可以用作特征对象,它们常规类型,但也需要某种间接来处理它们(引用或者Box).另一方面,你正在努力实现Parser裸机Trigger.裸露的特征是动态大小的类型,通常它们不能在普通大小类型的任何地方使用.

你真正想要的是Parser 为每种Trigger实现的类型实现.这可以用非常简单的方式编写:

impl<'a, T> Parser<'a> for T where T: Trigger {
  fn parse(&mut self, tokens: &'a [String]) -> Result<&'a [String], Error> {
    match self.pull() {
      Some(err) => Err(err),
      _         => Ok(tokens)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这就是所谓的毯式impl模式,它在标准库中广泛使用.但是,它有一些限制,例如,你将无法重新实现Parser任何特定的Trigger.

顺便说一句,考虑将特征中的'a生命周期参数移动到其方法中.使用此参数的方式很少有用(当然,这取决于您的实际代码,但仍然如此).