【发布时间】:2026-01-17 18:10:01
【问题描述】:
我有一个公共特征Parser,它定义了一个外部接口。然后我有一个私有的 ParserImpl 结构来实现这些方法(实际上,我有几个实现,这就是使用 trait 进行抽象的想法)。
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);
}
【问题讨论】:
-
我使用了一个函数来隐藏
ParserImpl——你为什么认为在这种情况下这样做很有价值? 这似乎是一个潜在的陷阱——你认为会发生什么样的陷阱? -
这是简化版。有多个解析器实现,它们都呈现相同的
Parser接口。其余代码需要与所使用的特定解析器无关。 -
你知道你可以implement a trait for a box of that trait吗?那么这个函数不必是执行装箱的函数。