如何在Rust中编程共享行为而不重复相同的代码在每个模块?



对于编写一个非常大的程序,我认为没有办法为每个使用某种共享行为的结构体编写相同的代码。

例如,狗可能会"吠叫":

struct Dog {
is_barking: bool,
....
}
impl Dog {
pub fn bark(self) {
self.is_barking = true;
emit_sound("b");
emit_sound("a");
emit_sound("r");
emit_sound("k");
self.is_barking = false;
}
....
}

这种狗可能有很多品种:

struct Poodle {
unique_poodle_val: &str
}
impl Poodle {
pub fn unique_behaviour(self) {
self.some_behaviour();
}
}
struct Rottweiler {
unique_rottweiler_val: u32
}
impl Rottweiler{
pub fn unique_behaviour(self) {
self.some_behaviour();
}
}
问题是,据我目前所知,Rust似乎无法做到这一点,但它需要这样做,我需要一个解决方案:
  1. 允许贵宾犬和罗威纳犬用完全相同的行为吠叫,而品种不需要考虑。
  2. 允许这是可能的,而不需要在每个品种模块中重新编码bark(),这是编程地狱,因为它导致重复的代码,每个模块都必须实现bark()。
  3. trait是相反的,不能访问结构体,所以默认trait实现不起作用。Rust不支持类似oop的继承,这里也不需要。

因此,我问:如果在每个模块中不重写bark(),怎么可能实现bark()呢?毕竟Poodle和Rottweiler的吠叫方式完全相同。

请提供一个如何在Rust代码中解决这个问题的例子,习惯的和稍微有点黑客的解决方案是受欢迎的,但请说明它们是什么,因为我还在学习Rust。谢谢你。

编辑:布尔不是一个线程的事情,而是在做某事之前设置一些状态的一个例子,即emit_sound在这个状态内。我们放入bark()中的任何代码都有同样的问题。这是对结构变量的访问,这是不可能的,比如,trait。

你已经指出了Rust目前做得不好的事情:简单地在结构体中添加基于内部数据和函数的行为。

解决这个问题的最典型的方法可能是将Barking隔离在一个由所有狗拥有的结构体中(当有疑问时,更倾向于组合而不是继承):

pub struct Barking {
is_barking: bool,
}
impl Barking {
pub fn do_it(&mut self) {
self.is_barking = true; // <- this makes no sense in rust, due to the ownership model
println!("bark");
println!("a");
println!("r");
println!("k");
self.is_barking = false;
}
}
struct Poodle {
unique_poodle_val: String,
barking: Barking,
}
impl Poodle {
pub fn unique_behaviour(self) {
println!("some_behaviour");
}
pub fn bark(&mut self) {
self.barking.do_it();
}
}
struct Rottweiler {
unique_rottweiler_val: u32,
barking: Barking,
}
impl Rottweiler{
pub fn unique_behaviour(self) {
println!("unique behavior");
}
pub fn bark(&mut self) {
// maybe decide to bite instead
self.barking.do_it();
}
}

在某些情况下,定义一个Barking特性是有意义的,使用一个通用的实现并声明一些函数来处理状态:

pub trait Barking {
fn bark(&mut self) {
self.set_barking(true);
println!("bark");
println!("a");
println!("r");
println!("k");
self.set_barking(false);
}
fn set_barking(&mut self, b: bool);
}
struct Poodle {
unique_poodle_val: String,
is_barking: bool,
}
impl Poodle {
pub fn unique_behaviour(self) {
println!("some_behaviour");
}
}
impl Barking for Poodle {
fn set_barking(&mut self, b: bool) {
self.is_barking = b;
}
}

请注意,这种半面向对象的方法通常会导致过于复杂和难以维护(就像OOP语言中的继承一样)。

相关内容

最新更新