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

2023-12-03

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

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

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. 特征是相反的,无法访问结构,因此默认特征实现不起作用。 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 特征是有意义的,具有通用的实现并声明一些函数来处理状态:

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 方法通常会变得过于复杂且难以维护(如 OOP 语言中的继承)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐