【问题标题】:Rust dependency inversion with nested structs using RC使用 RC 嵌套结构的 Rust 依赖反转
【发布时间】: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 }
  }
}

这是可行的,但这是实现依赖倒置的正确方法吗,就像我们在面向对象编程中通常所做的那样?

【问题讨论】:

  • 你可以使 Work generic 覆盖特征:play.rust-lang.org/…
  • ...或者,您可以使 Work 类型擦除依赖项:play.rust-lang.org/…
  • 非常感谢!我要研究这段代码,会有问题:)
  • 好消息是您的main() 和特征及其实现在两个 sn-ps 中完全没有变化。静态和动态调度之间唯一变化的是Work 的实现。您的Rc 尝试接近动态调度所需的内容,但没有理由使用Rc(您不共享所有权),Box 更合适。
  • 但是作为泛型选项比 Box 简单得多,使用 Box 比泛型有哪些好处?

标签: struct rust


【解决方案1】:

您可以通过工具使您的结构通用:

// 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<T> {
    tool: T,
}

impl<T: ToolTrait> Work<T> {
    // We can instantiate Work and set tool to it
    fn new(tool: T) -> Work<T> {
        Work { tool }
    }
}

fn main() {
    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"
}

【讨论】:

  • 有趣的想法!好多了,会试试这个
猜你喜欢
  • 2022-12-21
  • 2020-08-07
  • 2021-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多