Как мне создать структуру ссылок на признаки, если один объект может реализовать несколько признаков?

У меня есть структура, которая управляет несколькими датчиками. У меня есть гироскоп, акселерометр, магнитометр, барометр и термометр. Все это черты характера.

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

Мне нужно сделать его модульным, чтобы в файле конфигурации вы могли указать, какие датчики вы используете.

Проблема в том, что некоторые датчики перекрываются. Например: у одного человека может быть LSM9DS0, который содержит гироскоп, акселерометр и магнитометр, а у другого человека может быть гироскоп L3GD20 и акселерометр LSM303D, магнитометр.

В C ++ я бы сохранил указатели или ссылки, но я не уверен, как правильно реализовать это в Rust.

Краткая версия: необходимо иметь ссылки на каждый датчик как на члены этой структуры. Некоторые из этих ссылок относятся к одному и тому же объекту.


person Martin Deegan    schedule 06.08.2017    source источник


Ответы (1)


В C ++ я бы сохранил указатели или ссылки

Ржавчина не такая уж чужая. Вы делаете то же самое. Основное отличие состоит в том, что Rust не позволяет вам изменять одну вещь двумя разными путями или иметь висящую ссылку.

Ответ на ваш вопрос имеет множество потенциальных решений. Например, вы не описываете, нужно ли вам иметь возможность изменять датчики или описывать, переживут ли датчики диспетчер, будут ли задействованы потоки и т. Д. Все эти вещи влияют на то, насколько микрооптимизирован код. .

Максимально гибкое решение:

  1. используйте совместное владение, например предоставлено Rc или _ 2_. Это позволяет нескольким объектам владеть датчиком.

  2. используйте внутреннюю изменчивость, например эту предоставляется RefCell или _ 4_. Это перемещает принудительное применение одной изменяющейся ссылки за раз из времени компиляции во время выполнения.

  3. используйте типажные объекты для моделирования динамической диспетчеризации, поскольку решение о том, какие конкретные объекты использовать, принимается во время выполнения.

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 одновременно является признаком и типом, но у типа нет размера. на него всегда нужно ссылаться за указателем (&Barometer, Box<Barometer>, RefCell<Barometer> и т. д.)

Смотрите также:

person Shepmaster    schedule 06.08.2017