我开始了一个新项目,我希望尽可能模块化,我的意思是我希望将来能够替换其他部分。这似乎是traits
的完美用法,目前我有这段代码:
mod parser;
mod renderer;
mod renderers;
use parser::MarkParser;
use renderer::MarkRenderer;
struct Rustmark <P: MarkParser, R: MarkRenderer> {
parser: P,
renderer: R,
}
impl <P: MarkParser, R: MarkRenderer> Rustmark <P, R> {
fn new() -> Rustmark <P, R> {
Rustmark {
parser: parser::DefaultParser::new(),
renderer: renderers::HTMLRenderer::new(),
}
}
fn render(&self, input: &str) -> &str {
self.renderer.render(self.parser.parse(input))
}
}
但是我得到了一些错误,主要是这个错误:
错误:不匹配的类型: 预期
Rustmark<P, R>
, 找到Rustmark<parser::DefaultParser, renderers::html::HTMLRenderer>
(预期的类型参数, 找到了结构parser::DefaultParser
)[E0308]
和这样的一些终身错误:
由于需求冲突,错误无法推断自动强制的适当生命周期
帮助:考虑使用显式生命周期参数,如下所示:
fn parse<'a>(&'a self, input: &'a str) -> &str
我尝试了多次调整以使其工作,但它们似乎都没有安抚编译器。所以我想知道这是否是正确的方法以及我能做些什么来使其发挥作用。
答案 0 :(得分:4)
第一个错误:您使用类型为Rustmark
的字段parser
和类型为DefaultParser
的字段renderer
创建了一个HTMLRenderer
对象,但功能是预计会返回Rustmark <P, R>
。通常,P不是DefaultParser
类型而R不是HTMLRenderer
类型,因此它永远不会编译。如果您想要具有正确类型的默认值,那么一个好的解决方案是绑定P
和R
以实现Default
trait
,这样:
use std::default:Default;
impl <P: MarkParser + Default, R: MarkRenderer + Default> Rustmark <P, R> {
fn new() -> Rustmark <P, R> {
Rustmark {
parser: P::default(),
renderer: R:default(),
}
}
}
第二个错误:主要问题是你返回一个可能会死在render
方法内的引用(可能是你在内部String
方法中分配的render
)。编译器告诉您它不知道该引用所指向的对象的生命周期,因此无法保证该引用有效。您可以指定一个生命周期参数,但在您的情况下,最好的解决方案可能是返回String
对象本身,而不是引用。
答案 1 :(得分:3)
按照 Andrea P 的回答,我在std中查找了default
特征。其定义如下:
pub trait Default {
fn default() -> Self;
}
我最终做的不是使用default
特征,而是在我的new
和MarkParser
特征中添加构造函数 MarkRenderer
这样:
pub trait MarkParser {
fn new() -> Self;
fn parse(&self, input: &str) -> &str;
}
我不知道的关键部分是Self
关键字
通过这种方式,我可以像这样编写我的实现:
impl <P: MarkParser, R: MarkRenderer> Rustmark <P, R> {
fn new() -> Rustmark <P, R> {
Rustmark {
parser: P::new(),
renderer: R::new(),
}
}
fn render(&self, input: &str) -> &str {
self.renderer.render(self.parser.parse(input))
}
}
这与实施Default
特征完全相同,只是我使用new
代替default
我更喜欢和我不喜欢#39; t必须将Default
特征添加到RustMark的impl
。
impl <P: MarkParser, R: MarkRenderer> Rustmark <P, R> {
而不是
impl <P: MarkParser + Default, R: MarkRenderer + Default> Rustmark <P, R> {
非常感谢Andrea P指出我正确的方向。