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

时间:2014-12-09 15:21:54

标签: rust traits

所以,让我说我有两个小特征, Parser 触发 Parser 接受一段字符串,进行一些解析并返回字符串切片而不使用消耗的标记。出错时,会返回错误。 触发器就像 Parser 一样,除了它不期望任何令牌,因此它会做一些事情并可能返回错误。每个触发器都可以视为 Parser ,我想定义使该规则成为现实的函数。这就是我的直觉让我做的事情:

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
    }
  }
}

我收到此错误消息:

parsers.rs:37:33: 37:40 error: explicit lifetime bound required
parsers.rs:37 impl<'a> Parser<'a> for Trigger {
                                      ^~~~~~~

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

1 个答案:

答案 0 :(得分: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)
    }
  }
}

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

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