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

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

例如,Dog 可能会“吠叫”:

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. Traits 是相反的,不能访问结构体,因此 default-trait 实现不起作用。Rust 不支持类似 OOP 的继承,这里也不需要它。

因此,我问:既然贵宾犬和罗威纳犬的吠叫方式完全相同,那么如何在不重写每个模块中的 bark() 的情况下实现 bark() 呢?

请提供一个如何在 Rust 代码中解决此问题的示例,欢迎使用惯用的和稍微有点 hacky 的解决方案,但请说明它们是什么,因为我仍在学习 Rust。谢谢你。

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

回答

你已经指出了 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 trait 是有意义的,它有一个通用的实现并声明一些函数来处理状态:

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();
    }
}

请注意,这种半 OOP 方法通常会变得过于复杂且不易维护(如 OOP 语言中的继承)。


以上是如何在Rust中编写共享行为而不在每个模块中重复相同的代码?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>