代码之家  ›  专栏  ›  技术社区  ›  Martin Deegan

当一个对象可能实现多个特征时,如何创建特征引用结构?

  •  1
  • Martin Deegan  · 技术社区  · 7 年前

    我有一个管理多个传感器的结构。我有陀螺仪、加速计、磁强计、气压计和温度计。所有这些都是特征。

    pub struct SensorManager {
        barometer: Barometer + Sized,
        thermometer: Thermometer + Sized,
        gyroscope: Gyroscope + Sized,
        accelerometer: Accelerometer + Sized,
        magnetometer: Magnetometer + Sized
    }
    

    我需要将其模块化,以便在配置文件中指定正在使用的传感器。

    问题是一些传感器重叠。例如:一个人可以有一个包含陀螺仪、加速计和磁强计的LSM9DS0,而另一个人可以有一个L3GD20陀螺仪和一个LSM303D加速计、磁强计。

    简短版本:需要引用每个传感器作为此结构的成员。其中一些引用属于同一对象。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Shepmaster Tim Diekmann    4 年前

    在C++中,我会存储指针或引用

    锈并不是那么陌生。你做同样的事情。主要的区别在于,锈蚀阻止你通过两条不同的路径变异一件事,或者有一个悬而未决的引用。

    回答你的问题 许多的

    最灵活的解决方案是:

    1. 使用 shared ownership ,例如 Rc Arc

    2. 使用 interior mutability ,例如 RefCell Mutex

    3. trait objects 对动态调度进行建模,因为在运行时决定使用哪些具体对象。

    use std::{cell::RefCell, rc::Rc};
    
    trait Barometer {
        fn get(&self) -> i32;
        fn set(&self, value: i32);
    }
    
    trait Thermometer {
        fn get(&self) -> i32;
        fn set(&self, value: i32);
    }
    
    trait Gyroscope {
        fn get(&self) -> i32;
        fn set(&self, value: i32);
    }
    
    struct Multitudes;
    impl Barometer for Multitudes {
        fn get(&self) -> i32 {
            1
        }
        fn set(&self, value: i32) {
            println!("Multitudes barometer set to {}", value)
        }
    }
    
    impl Thermometer for Multitudes {
        fn get(&self) -> i32 {
            2
        }
        fn set(&self, value: i32) {
            println!("Multitudes thermometer set to {}", value)
        }
    }
    
    struct AutoGyro;
    
    impl Gyroscope for AutoGyro {
        fn get(&self) -> i32 {
            3
        }
        fn set(&self, value: i32) {
            println!("AutoGyro gyroscope set to {}", value)
        }
    }
    
    struct SensorManager {
        barometer: Rc<RefCell<dyn Barometer>>,
        thermometer: Rc<RefCell<dyn Thermometer>>,
        gyroscope: Rc<RefCell<dyn Gyroscope>>,
    }
    
    impl SensorManager {
        fn new(
            barometer: Rc<RefCell<dyn Barometer>>,
            thermometer: Rc<RefCell<dyn Thermometer>>,
            gyroscope: Rc<RefCell<dyn Gyroscope>>,
        ) -> Self {
            Self {
                barometer,
                thermometer,
                gyroscope,
            }
        }
    
        fn dump_info(&self) {
            let barometer = self.barometer.borrow();
            let thermometer = self.thermometer.borrow();
            let gyroscope = self.gyroscope.borrow();
    
            println!(
                "{}, {}, {}",
                barometer.get(),
                thermometer.get(),
                gyroscope.get()
            );
        }
    
        fn update(&self) {
            self.barometer.borrow_mut().set(42);
            self.thermometer.borrow_mut().set(42);
            self.gyroscope.borrow_mut().set(42);
        }
    }
    
    fn main() {
        let multi = Rc::new(RefCell::new(Multitudes));
        let gyro = Rc::new(RefCell::new(AutoGyro));
    
        let manager = SensorManager::new(multi.clone(), multi, gyro);
    
        manager.dump_info();
        manager.update();
    }
    

    Complete example on the Playground


    barometer: Barometer + Sized,
    

    你真的不想这样。 Barometer 特质 和a ,但类型没有大小。它总是需要在指针后面引用( &Barometer Box<Barometer> , RefCell<Barometer>