【发布时间】:2023-04-07 14:16:01
【问题描述】:
我正在尝试在 Rust 中做一些依赖反转。我的目标是创建一个结构,它接受任何其他符合特征的结构实例。
这不会编译,但基本上是我想要实现的:
// Trait for any kind of tool I may use in my work
trait ToolTrait {
fn do_work(&self);
}
struct Saw {
size: i32,
}
impl ToolTrait for Saw {
fn do_work(&self) {
println!("I'm a saw, size: {}cm", self.size);
}
}
struct ScrewDriver {
size: i32,
}
impl ToolTrait for ScrewDriver {
fn do_work(&self) {
println!("I'm a screwdriver, size: {}mm", self.size);
}
}
// Work uses any struct that complies with ToolTrait
pub struct Work {
tool: ToolTrait,
}
impl Work {
// We can instantiate Work and set tool to it
fn new(tool: ToolTrait) -> Work {
Work { tool }
}
}
let saw = Saw { size: 30 };
let work_1 = Work::new(saw);
work_1.tool.do_work(); // "I'm a saw, size: 30cm"
let screwdriver = ScrewDriver { size: 4 };
let work_2 = Work::new(screwdriver);
work_2.tool.do_work(); // "I'm a screwdriver, size: 4mm"
现在,关于 Rust 编译器,我们有几个错误警告:
pub struct Work {
tool: ToolTrait,
}
// trait objects without an explicit `dyn` are deprecated
好的,让我们在Work 和impl Work 中都添加dyn:
pub struct Work {
tool: dyn ToolTrait,
}
impl Work {
fn new(tool: dyn ToolTrait) -> Work {
Work {
tool: Rc::new(tool),
}
}
}
完美,Work 没有错误。但是关注impl Work 我们有这个错误:
impl Work {
fn new(tool: ToolTrait) -> Work {
Work {
tool: Rc::new(tool),
}
}
}
// the size for values of type `(dyn main::ToolTrait + 'static)` cannot be known at compilation time
有道理:Work 无法知道tool 的大小。但是我该如何解决呢?
我将dyn ToolTrait 与std::rc::Rc 包装成Rc<dyn ToolTrait>:
pub struct Work {
tool: Rc<dyn ToolTrait>,
}
impl Work {
// We can instantiate Work and set tool to it
fn new(tool: Rc<dyn ToolTrait>) -> Work {
Work { tool }
}
}
这是可行的,但这是实现依赖倒置的正确方法吗,就像我们在面向对象编程中通常所做的那样?
【问题讨论】:
-
你可以使
Workgeneric 覆盖特征:play.rust-lang.org/… -
...或者,您可以使
Work类型擦除依赖项:play.rust-lang.org/… -
非常感谢!我要研究这段代码,会有问题:)
-
好消息是您的
main()和特征及其实现在两个 sn-ps 中完全没有变化。静态和动态调度之间唯一变化的是Work的实现。您的Rc尝试接近动态调度所需的内容,但没有理由使用Rc(您不共享所有权),Box更合适。 -
但是作为泛型选项比 Box 简单得多,使用 Box 比泛型有哪些好处?