1

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

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

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

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

在 C++ 中,我会存储指针或引用,但我不确定如何在 Rust 中安全地正确实现它。

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

4

1 回答 1

2

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

Rust 并不是那么陌生。你做同样的事情。主要区别在于,Rust 阻止您通过两条不同的路径改变一件事或让引用悬空。

回答您的问题有许多潜在的解决方案。例如,您没有描述是否需要能够改变传感器或描述传感器是否会比管理器寿命更长,是否会涉及线程等。所有这些都会影响代码的微优化程度.

最灵活的解决方案是:

  1. 使用共享所有权,例如由Rcor提供的所有权Arc。这允许多个事物拥有传感器。

  2. 使用内部可变性,例如RefCellor提供的Mutex。这将一次执行单个变异引用从编译时移动到运行时。

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

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

操场上的完整示例


barometer: Barometer + Sized,

你真的不想这样做。Barometer既是trait又是type,但 type 没有大小。它总是需要在指针后面引用(&Barometer, Box<Barometer>,RefCell<Barometer>等)

也可以看看:

于 2017-08-06T17:21:32.870 回答