我有一个公共特征Parser
,它定义了一个外部接口。然后我有一个私有的ParserImpl
结构来实现这些方法(实际上,我有几个实现,这是使用特征抽象的背后的想法)。
use std::io;
pub trait Parser {
// ...omitted
}
struct ParserImpl<R: io::Read> {
// ...omitted
stream: R,
}
impl<R: io::Read> ParserImpl<R> {
// ...methods
fn new(stream: R) -> ParserImpl<R> {
ParserImpl {
// ...omitted
stream: stream,
}
}
}
impl<R: io::Read> Parser for ParserImpl<R> {
// ...methods
}
要创建解析器实例,我使用函数隐藏ParserImpl
。
pub fn make_parser<'a, R>(stream: R) -> Box<Parser + 'a>
where
R: io::Read + 'a,
{
Box::new(ParserImpl::new(stream))
}
这一切都很好......而且它有效......但make_parser
功能使我烦恼。我觉得必须有一种更简单的方法来解决这个问题,因为我错过了一些重要的东西,因为这似乎是一个潜在的陷阱,只要使用像io::Read
这样的特征来抽象出数据来源。
我理解需要指定生命周期(Parameter type may not live long enough?),但我有点难过我是否可以同时拥有一个干净简单的界面,并且还使用像io::Read
这样的特征。
使用io::Read
等我缺少的特征是否有“更清洁”或更为惯用的方法?如果没有,那没关系,但我对Rust很陌生,当我编写上述函数时,我一直在想“这不可能......”
要使此示例可运行,请执行main
:
fn main() {
use std::fs;
let file: fs::File = fs::File::open("blabby.txt").unwrap();
let parser = make_parser(file);
}
答案 0 :(得分:0)
是编写具有该含义的代码的惯用方式,但您可能不需要这种意义。
例如,如果您不需要来创建盒装特征对象,则可以直接返回参数化值,或者在这种情况下只使用{{1}的结果}。这是我的默认形式,直到我知道我需要一些特质对象提供的动态调度。
您还可能需要ParserImpl::new
生命周期,而不是引入新的生命周期'static
,但这会减少您可以传递到'a
的允许类型的范围:
make_parser