Rust 练习册 95:React与响应式编程

响应式编程是一种编程范式,专注于数据流和变化传播。在 Exercism 的 "react" 练习中,我们需要实现一个简单的响应式系统,类似于 ReactJS 或其他前端框架中的状态管理系统。这不仅能帮助我们掌握响应式编程的核心概念,还能深入学习Rust中的所有权、生命周期、闭包和复杂数据结构设计。

什么是响应式编程?

响应式编程是一种声明式的编程范式,关注于数据流和变化传播。在响应式系统中,当数据发生变化时,相关的计算会自动重新执行,依赖这些计算的组件也会自动更新。

在这个练习中,我们需要实现一个简单的响应式系统,包含以下组件:

  1. 输入单元(Input Cells):包含可变值的基本单元
  2. 计算单元(Compute Cells):基于其他单元的值进行计算的单元
  3. 回调(Callbacks):当计算单元的值发生变化时触发的函数

让我们先看看练习提供的结构体和函数:

rust 复制代码
/// `InputCellId` is a unique identifier for an input cell.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct InputCellId();
/// `ComputeCellId` is a unique identifier for a compute cell.
/// Values of type `InputCellId` and `ComputeCellId` should not be mutually assignable,
/// demonstrated by the following tests:
///
/// ```compile_fail
/// let mut r = react::Reactor::new();
/// let input: react::ComputeCellId = r.create_input(111);
/// ```
///
/// ```compile_fail
/// let mut r = react::Reactor::new();
/// let input = r.create_input(111);
/// let compute: react::InputCellId = r.create_compute(&[react::CellId::Input(input)], |_| 222).unwrap();
/// ```
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ComputeCellId();
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CallbackId();

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CellId {
    Input(InputCellId),
    Compute(ComputeCellId),
}

#[derive(Debug, PartialEq)]
pub enum RemoveCallbackError {
    NonexistentCell,
    NonexistentCallback,
}

pub struct Reactor<T> {
    // Just so that the compiler doesn't complain about an unused type parameter.
    // You probably want to delete this field.
    dummy: ::std::marker::PhantomData<T>,
}

// You are guaranteed that Reactor will only be tested against types that are Copy + PartialEq.
impl<T: Copy + PartialEq> Reactor<T> {
    pub fn new() -> Self {
        unimplemented!()
    }

    // Creates an input cell with the specified initial value, returning its ID.
    pub fn create_input(&mut self, _initial: T) -> InputCellId {
        unimplemented!()
    }

    // Creates a compute cell with the specified dependencies and compute function.
    // The compute function is expected to take in its arguments in the same order as specified in
    // `dependencies`.
    // You do not need to reject compute functions that expect more arguments than there are
    // dependencies (how would you check for this, anyway?).
    //
    // If any dependency doesn't exist, returns an Err with that nonexistent dependency.
    // (If multiple dependencies do not exist, exactly which one is returned is not defined and
    // will not be tested)
    //
    // Notice that there is no way to *remove* a cell.
    // This means that you may assume, without checking, that if the dependencies exist at creation
    // time they will continue to exist as long as the Reactor exists.
    pub fn create_compute<F: Fn(&[T]) -> T>(
        &mut self,
        _dependencies: &[CellId],
        _compute_func: F,
    ) -> Result<ComputeCellId, CellId> {
        unimplemented!()
    }

    // Retrieves the current value of the cell, or None if the cell does not exist.
    //
    // You may wonder whether it is possible to implement `get(&self, id: CellId) -> Option<&Cell>`
    // and have a `value(&self)` method on `Cell`.
    //
    // It turns out this introduces a significant amount of extra complexity to this exercise.
    // We chose not to cover this here, since this exercise is probably enough work as-is.
    pub fn value(&self, id: CellId) -> Option<T> {
        unimplemented!("Get the value of the cell whose id is {:?}", id)
    }

    // Sets the value of the specified input cell.
    //
    // Returns false if the cell does not exist.
    //
    // Similarly, you may wonder about `get_mut(&mut self, id: CellId) -> Option<&mut Cell>`, with
    // a `set_value(&mut self, new_value: T)` method on `Cell`.
    //
    // As before, that turned out to add too much extra complexity.
    pub fn set_value(&mut self, _id: InputCellId, _new_value: T) -> bool {
        unimplemented!()
    }

    // Adds a callback to the specified compute cell.
    //
    // Returns the ID of the just-added callback, or None if the cell doesn't exist.
    //
    // Callbacks on input cells will not be tested.
    //
    // The semantics of callbacks (as will be tested):
    // For a single set_value call, each compute cell's callbacks should each be called:
    // * Zero times if the compute cell's value did not change as a result of the set_value call.
    // * Exactly once if the compute cell's value changed as a result of the set_value call.
    //   The value passed to the callback should be the final value of the compute cell after the
    //   set_value call.
    pub fn add_callback<F: FnMut(T)>(
        &mut self,
        _id: ComputeCellId,
        _callback: F,
    ) -> Option<CallbackId> {
        unimplemented!()
    }

    // Removes the specified callback, using an ID returned from add_callback.
    //
    // Returns an Err if either the cell or callback does not exist.
    //
    // A removed callback should no longer be called.
    pub fn remove_callback(
        &mut self,
        cell: ComputeCellId,
        callback: CallbackId,
    ) -> Result<(), RemoveCallbackError> {
        unimplemented!(
            "Remove the callback identified by the CallbackId {:?} from the cell {:?}",
            callback,
            cell,
        )
    }
}

我们需要实现 Reactor 结构体,使其能够管理输入单元、计算单元和回调函数,形成一个简单的响应式系统。

设计分析

1. 核心要求

  1. 单元管理:管理输入单元和计算单元的创建和存储
  2. 依赖跟踪:跟踪计算单元对其依赖单元的依赖关系
  3. 值传播:当输入单元值改变时,自动更新相关计算单元
  4. 回调机制:当计算单元值发生变化时触发回调函数
  5. 类型安全:确保 InputCellId 和 ComputeCellId 不能互换使用

2. 技术要点

  1. 所有权和生命周期:正确管理单元和回调函数的所有权
  2. 闭包处理:存储和调用可变闭包
  3. 数据结构设计:设计合适的数据结构存储单元和依赖关系
  4. 变化检测:检测值的变化以决定是否触发回调
  5. 错误处理:处理不存在的单元和回调

完整实现

1. 基础实现

rust 复制代码
use std::collections::HashMap;

/// `InputCellId` is a unique identifier for an input cell.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct InputCellId(usize);

/// `ComputeCellId` is a unique identifier for a compute cell.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ComputeCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CallbackId(usize);

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CellId {
    Input(InputCellId),
    Compute(ComputeCellId),
}

#[derive(Debug, PartialEq)]
pub enum RemoveCallbackError {
    NonexistentCell,
    NonexistentCallback,
}

// 输入单元
struct InputCell<T> {
    value: T,
}

// 计算单元
struct ComputeCell<T> {
    dependencies: Vec<CellId>,
    compute_func: Box<dyn Fn(&[T]) -> T>,
    value: T,
    callbacks: HashMap<CallbackId, Box<dyn FnMut(T)>>,
}

pub struct Reactor<T: Copy + PartialEq> {
    input_cells: HashMap<InputCellId, InputCell<T>>,
    compute_cells: HashMap<ComputeCellId, ComputeCell<T>>,
    next_input_id: usize,
    next_compute_id: usize,
    next_callback_id: usize,
}

impl<T: Copy + PartialEq> Reactor<T> {
    pub fn new() -> Self {
        Reactor {
            input_cells: HashMap::new(),
            compute_cells: HashMap::new(),
            next_input_id: 0,
            next_compute_id: 0,
            next_callback_id: 0,
        }
    }

    // Creates an input cell with the specified initial value, returning its ID.
    pub fn create_input(&mut self, initial: T) -> InputCellId {
        let id = InputCellId(self.next_input_id);
        self.next_input_id += 1;
        self.input_cells.insert(id, InputCell { value: initial });
        id
    }

    // Creates a compute cell with the specified dependencies and compute function.
    pub fn create_compute<F: Fn(&[T]) -> T + 'static>(
        &mut self,
        dependencies: &[CellId],
        compute_func: F,
    ) -> Result<ComputeCellId, CellId> {
        // 检查所有依赖是否存在
        for &dep in dependencies {
            match dep {
                CellId::Input(id) => {
                    if !self.input_cells.contains_key(&id) {
                        return Err(CellId::Input(id));
                    }
                }
                CellId::Compute(id) => {
                    if !self.compute_cells.contains_key(&id) {
                        return Err(CellId::Compute(id));
                    }
                }
            }
        }

        // 计算初始值
        let values: Vec<T> = dependencies
            .iter()
            .map(|&dep| self.value(dep).unwrap())
            .collect();
        let initial_value = compute_func(&values);

        let id = ComputeCellId(self.next_compute_id);
        self.next_compute_id += 1;
        
        let compute_cell = ComputeCell {
            dependencies: dependencies.to_vec(),
            compute_func: Box::new(compute_func),
            value: initial_value,
            callbacks: HashMap::new(),
        };
        
        self.compute_cells.insert(id, compute_cell);
        Ok(id)
    }

    // Retrieves the current value of the cell, or None if the cell does not exist.
    pub fn value(&self, id: CellId) -> Option<T> {
        match id {
            CellId::Input(id) => self.input_cells.get(&id).map(|cell| cell.value),
            CellId::Compute(id) => self.compute_cells.get(&id).map(|cell| cell.value),
        }
    }

    // Sets the value of the specified input cell.
    pub fn set_value(&mut self, id: InputCellId, new_value: T) -> bool {
        let cell = match self.input_cells.get_mut(&id) {
            Some(cell) => cell,
            None => return false,
        };

        if cell.value == new_value {
            return true;
        }

        cell.value = new_value;
        self.update_dependents(CellId::Input(id));
        true
    }

    // 添加回调函数
    pub fn add_callback<F: FnMut(T) + 'static>(
        &mut self,
        id: ComputeCellId,
        callback: F,
    ) -> Option<CallbackId> {
        let cell = self.compute_cells.get_mut(&id)?;
        let callback_id = CallbackId(self.next_callback_id);
        self.next_callback_id += 1;
        cell.callbacks.insert(callback_id, Box::new(callback));
        Some(callback_id)
    }

    // 移除回调函数
    pub fn remove_callback(
        &mut self,
        cell_id: ComputeCellId,
        callback_id: CallbackId,
    ) -> Result<(), RemoveCallbackError> {
        let cell = self
            .compute_cells
            .get_mut(&cell_id)
            .ok_or(RemoveCallbackError::NonexistentCell)?;
            
        if cell.callbacks.remove(&callback_id).is_some() {
            Ok(())
        } else {
            Err(RemoveCallbackError::NonexistentCallback)
        }
    }

    // 更新依赖单元
    fn update_dependents(&mut self, changed_cell: CellId) {
        let mut affected_cells = Vec::new();
        
        // 找到所有直接依赖于 changed_cell 的计算单元
        for (&id, cell) in &self.compute_cells {
            if cell.dependencies.contains(&changed_cell) {
                affected_cells.push(id);
            }
        }
        
        // 递归更新所有受影响的计算单元
        self.update_compute_cells(affected_cells);
    }

    // 更新计算单元
    fn update_compute_cells(&mut self, cells_to_update: Vec<ComputeCellId>) {
        for id in cells_to_update {
            if let Some(cell) = self.compute_cells.get(&id) {
                let dependencies = cell.dependencies.clone();
                let compute_func = &cell.compute_func;
                
                let values: Vec<T> = dependencies
                    .iter()
                    .map(|&dep| self.value(dep).unwrap())
                    .collect();
                
                let new_value = compute_func(&values);
                
                if let Some(cell) = self.compute_cells.get_mut(&id) {
                    let old_value = cell.value;
                    cell.value = new_value;
                    
                    // 如果值发生变化,调用回调函数
                    if old_value != new_value {
                        let callbacks: Vec<(CallbackId, Box<dyn FnMut(T)>)> = 
                            cell.callbacks.drain().collect();
                        
                        for (callback_id, mut callback) in callbacks {
                            callback(new_value);
                            cell.callbacks.insert(callback_id, callback);
                        }
                    }
                    
                    // 继续更新依赖于此单元的其他单元
                    self.update_dependents(CellId::Compute(id));
                }
            }
        }
    }
}

2. 优化实现

rust 复制代码
use std::collections::HashMap;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InputCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ComputeCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct CallbackId(usize);

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CellId {
    Input(InputCellId),
    Compute(ComputeCellId),
}

#[derive(Debug, PartialEq)]
pub enum RemoveCallbackError {
    NonexistentCell,
    NonexistentCallback,
}

struct InputCell<T> {
    value: T,
}

struct ComputeCell<T> {
    dependencies: Vec<CellId>,
    reverse_dependencies: Vec<ComputeCellId>,
    compute_func: Box<dyn Fn(&[T]) -> T>,
    value: T,
    callbacks: HashMap<CallbackId, Box<dyn FnMut(T)>>,
}

pub struct Reactor<T: Copy + PartialEq> {
    input_cells: HashMap<InputCellId, InputCell<T>>,
    compute_cells: HashMap<ComputeCellId, ComputeCell<T>>,
    next_input_id: usize,
    next_compute_id: usize,
    next_callback_id: usize,
}

impl<T: Copy + PartialEq> Reactor<T> {
    pub fn new() -> Self {
        Reactor {
            input_cells: HashMap::new(),
            compute_cells: HashMap::new(),
            next_input_id: 0,
            next_compute_id: 0,
            next_callback_id: 0,
        }
    }

    pub fn create_input(&mut self, initial: T) -> InputCellId {
        let id = InputCellId(self.next_input_id);
        self.next_input_id += 1;
        self.input_cells.insert(id, InputCell { value: initial });
        id
    }

    pub fn create_compute<F: Fn(&[T]) -> T + 'static>(
        &mut self,
        dependencies: &[CellId],
        compute_func: F,
    ) -> Result<ComputeCellId, CellId> {
        // 检查所有依赖是否存在
        for &dep in dependencies {
            match dep {
                CellId::Input(id) => {
                    if !self.input_cells.contains_key(&id) {
                        return Err(CellId::Input(id));
                    }
                }
                CellId::Compute(id) => {
                    if !self.compute_cells.contains_key(&id) {
                        return Err(CellId::Compute(id));
                    }
                }
            }
        }

        // 计算初始值
        let values: Vec<T> = dependencies
            .iter()
            .map(|&dep| self.value(dep).unwrap())
            .collect();
        let initial_value = compute_func(&values);

        let id = ComputeCellId(self.next_compute_id);
        self.next_compute_id += 1;
        
        // 更新反向依赖关系
        for &dep in dependencies {
            if let CellId::Compute(dep_id) = dep {
                if let Some(dep_cell) = self.compute_cells.get_mut(&dep_id) {
                    dep_cell.reverse_dependencies.push(id);
                }
            }
        }
        
        let compute_cell = ComputeCell {
            dependencies: dependencies.to_vec(),
            reverse_dependencies: Vec::new(),
            compute_func: Box::new(compute_func),
            value: initial_value,
            callbacks: HashMap::new(),
        };
        
        self.compute_cells.insert(id, compute_cell);
        Ok(id)
    }

    pub fn value(&self, id: CellId) -> Option<T> {
        match id {
            CellId::Input(id) => self.input_cells.get(&id).map(|cell| cell.value),
            CellId::Compute(id) => self.compute_cells.get(&id).map(|cell| cell.value),
        }
    }

    pub fn set_value(&mut self, id: InputCellId, new_value: T) -> bool {
        let cell = match self.input_cells.get_mut(&id) {
            Some(cell) => cell,
            None => return false,
        };

        if cell.value == new_value {
            return true;
        }

        cell.value = new_value;
        self.update_dependents(CellId::Input(id));
        true
    }

    pub fn add_callback<F: FnMut(T) + 'static>(
        &mut self,
        id: ComputeCellId,
        callback: F,
    ) -> Option<CallbackId> {
        let cell = self.compute_cells.get_mut(&id)?;
        let callback_id = CallbackId(self.next_callback_id);
        self.next_callback_id += 1;
        cell.callbacks.insert(callback_id, Box::new(callback));
        Some(callback_id)
    }

    pub fn remove_callback(
        &mut self,
        cell_id: ComputeCellId,
        callback_id: CallbackId,
    ) -> Result<(), RemoveCallbackError> {
        let cell = self
            .compute_cells
            .get_mut(&cell_id)
            .ok_or(RemoveCallbackError::NonexistentCell)?;
            
        if cell.callbacks.remove(&callback_id).is_some() {
            Ok(())
        } else {
            Err(RemoveCallbackError::NonexistentCallback)
        }
    }

    fn update_dependents(&mut self, changed_cell: CellId) {
        let dependents = match changed_cell {
            CellId::Input(_) => {
                // 收集直接依赖于该输入单元的所有计算单元
                self.compute_cells
                    .iter()
                    .filter_map(|(&id, cell)| {
                        if cell.dependencies.contains(&changed_cell) {
                            Some(id)
                        } else {
                            None
                        }
                    })
                    .collect::<Vec<_>>()
            }
            CellId::Compute(id) => {
                // 使用反向依赖关系
                if let Some(cell) = self.compute_cells.get(&id) {
                    cell.reverse_dependencies.clone()
                } else {
                    Vec::new()
                }
            }
        };
        
        self.update_compute_cells(dependents);
    }

    fn update_compute_cells(&mut self, cells_to_update: Vec<ComputeCellId>) {
        for id in cells_to_update {
            if let Some(cell) = self.compute_cells.get(&id) {
                let dependencies = cell.dependencies.clone();
                let compute_func = &cell.compute_func;
                
                let values: Vec<T> = dependencies
                    .iter()
                    .map(|&dep| self.value(dep).unwrap())
                    .collect();
                
                let new_value = compute_func(&values);
                
                if let Some(cell) = self.compute_cells.get_mut(&id) {
                    let old_value = cell.value;
                    cell.value = new_value;
                    
                    // 如果值发生变化,调用回调函数
                    if old_value != new_value {
                        let callbacks: Vec<(CallbackId, Box<dyn FnMut(T)>)> = 
                            cell.callbacks.iter_mut()
                            .map(|(&id, callback)| (id, std::mem::replace(callback, Box::new(|_| {}))))
                            .collect();
                        
                        for (callback_id, mut callback) in callbacks {
                            callback(new_value);
                            cell.callbacks.insert(callback_id, callback);
                        }
                    }
                    
                    // 继续更新依赖于此单元的其他单元
                    if old_value != new_value {
                        self.update_dependents(CellId::Compute(id));
                    }
                }
            }
        }
    }
}

测试用例分析

通过查看测试用例,我们可以更好地理解需求:

rust 复制代码
#[test]
fn input_cells_have_a_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(10);
    assert_eq!(reactor.value(CellId::Input(input)), Some(10));
}

输入单元应该有初始值。

rust 复制代码
#[test]
fn an_input_cells_value_can_be_set() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(4);
    assert!(reactor.set_value(input, 20));
    assert_eq!(reactor.value(CellId::Input(input)), Some(20));
}

输入单元的值可以被设置。

rust 复制代码
#[test]
fn error_setting_a_nonexistent_input_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(!Reactor::new().set_value(input, 0));
}

设置不存在的输入单元应该返回false。

rust 复制代码
#[test]
fn compute_cells_calculate_initial_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor
        .create_compute(&[CellId::Input(input)], |v| v[0] + 1)
        .unwrap();
    assert_eq!(reactor.value(CellId::Compute(output)), Some(2));
}

计算单元应该计算初始值。

rust 复制代码
#[test]
fn compute_cells_take_inputs_in_the_right_order() {
    let mut reactor = Reactor::new();
    let one = reactor.create_input(1);
    let two = reactor.create_input(2);
    let output = reactor
        .create_compute(&[CellId::Input(one), CellId::Input(two)], |v| {
            v[0] + v[1] * 10
        })
        .unwrap();
    assert_eq!(reactor.value(CellId::Compute(output)), Some(21));
}

计算单元应该按照依赖顺序接收输入。

rust 复制代码
#[test]
fn error_creating_compute_cell_if_input_doesnt_exist() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert_eq!(
        Reactor::new().create_compute(&[CellId::Input(input)], |_| 0),
        Err(CellId::Input(input))
    );
}

如果依赖不存在,创建计算单元应该返回错误。

rust 复制代码
#[test]
fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() {
    let mut dummy_reactor = Reactor::new();
    let _ = dummy_reactor.create_input(1);
    let dummy_cell = dummy_reactor.create_input(2);
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    assert_eq!(
        reactor.create_compute(&[CellId::Input(input), CellId::Input(dummy_cell)], |_| 0),
        Err(CellId::Input(dummy_cell))
    );
    assert!(reactor.set_value(input, 5));
    assert_eq!(reactor.value(CellId::Input(input)), Some(5));
}

创建计算单元时,即使有有效和无效的输入,也不应该破坏现有单元。

rust 复制代码
#[test]
fn compute_cells_update_value_when_dependencies_are_changed() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor
        .create_compute(&[CellId::Input(input)], |v| v[0] + 1)
        .unwrap();
    assert_eq!(reactor.value(CellId::Compute(output)), Some(2));
    assert!(reactor.set_value(input, 3));
    assert_eq!(reactor.value(CellId::Compute(output)), Some(4));
}

当依赖改变时,计算单元应该更新值。

rust 复制代码
#[test]
fn compute_cells_can_depend_on_other_compute_cells() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let times_two = reactor
        .create_compute(&[CellId::Input(input)], |v| v[0] * 2)
        .unwrap();
    let times_thirty = reactor
        .create_compute(&[CellId::Input(input)], |v| v[0] * 30)
        .unwrap();
    let output = reactor
        .create_compute(
            &[CellId::Compute(times_two), CellId::Compute(times_thirty)],
            |v| v[0] + v[1],
        )
        .unwrap();
    assert_eq!(reactor.value(CellId::Compute(output)), Some(32));
    assert!(reactor.set_value(input, 3));
    assert_eq!(reactor.value(CellId::Compute(output)), Some(96));
}

计算单元可以依赖于其他计算单元。

性能优化版本

考虑性能的优化实现:

rust 复制代码
use std::collections::HashMap;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InputCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ComputeCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct CallbackId(usize);

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CellId {
    Input(InputCellId),
    Compute(ComputeCellId),
}

#[derive(Debug, PartialEq)]
pub enum RemoveCallbackError {
    NonexistentCell,
    NonexistentCallback,
}

struct InputCell<T> {
    value: T,
}

struct ComputeCell<T> {
    dependencies: Vec<CellId>,
    reverse_dependencies: Vec<ComputeCellId>,
    compute_func: Box<dyn Fn(&[T]) -> T>,
    value: T,
    callbacks: HashMap<CallbackId, Box<dyn FnMut(T)>>,
}

pub struct Reactor<T: Copy + PartialEq> {
    input_cells: HashMap<InputCellId, InputCell<T>>,
    compute_cells: HashMap<ComputeCellId, ComputeCell<T>>,
    next_input_id: usize,
    next_compute_id: usize,
    next_callback_id: usize,
}

impl<T: Copy + PartialEq> Reactor<T> {
    pub fn new() -> Self {
        Reactor {
            input_cells: HashMap::new(),
            compute_cells: HashMap::new(),
            next_input_id: 0,
            next_compute_id: 0,
            next_callback_id: 0,
        }
    }

    pub fn create_input(&mut self, initial: T) -> InputCellId {
        let id = InputCellId(self.next_input_id);
        self.next_input_id += 1;
        self.input_cells.insert(id, InputCell { value: initial });
        id
    }

    pub fn create_compute<F: Fn(&[T]) -> T + 'static>(
        &mut self,
        dependencies: &[CellId],
        compute_func: F,
    ) -> Result<ComputeCellId, CellId> {
        // 检查所有依赖是否存在
        for &dep in dependencies {
            match dep {
                CellId::Input(id) => {
                    if !self.input_cells.contains_key(&id) {
                        return Err(CellId::Input(id));
                    }
                }
                CellId::Compute(id) => {
                    if !self.compute_cells.contains_key(&id) {
                        return Err(CellId::Compute(id));
                    }
                }
            }
        }

        // 计算初始值
        let values: Vec<T> = dependencies
            .iter()
            .map(|&dep| self.value(dep).unwrap())
            .collect();
        let initial_value = compute_func(&values);

        let id = ComputeCellId(self.next_compute_id);
        self.next_compute_id += 1;
        
        // 更新反向依赖关系
        for &dep in dependencies {
            if let CellId::Compute(dep_id) = dep {
                if let Some(dep_cell) = self.compute_cells.get_mut(&dep_id) {
                    dep_cell.reverse_dependencies.push(id);
                }
            }
        }
        
        let compute_cell = ComputeCell {
            dependencies: dependencies.to_vec(),
            reverse_dependencies: Vec::new(),
            compute_func: Box::new(compute_func),
            value: initial_value,
            callbacks: HashMap::new(),
        };
        
        self.compute_cells.insert(id, compute_cell);
        Ok(id)
    }

    pub fn value(&self, id: CellId) -> Option<T> {
        match id {
            CellId::Input(id) => self.input_cells.get(&id).map(|cell| cell.value),
            CellId::Compute(id) => self.compute_cells.get(&id).map(|cell| cell.value),
        }
    }

    pub fn set_value(&mut self, id: InputCellId, new_value: T) -> bool {
        let cell = match self.input_cells.get_mut(&id) {
            Some(cell) => cell,
            None => return false,
        };

        if cell.value == new_value {
            return true;
        }

        cell.value = new_value;
        self.update_dependents(CellId::Input(id));
        true
    }

    pub fn add_callback<F: FnMut(T) + 'static>(
        &mut self,
        id: ComputeCellId,
        callback: F,
    ) -> Option<CallbackId> {
        let cell = self.compute_cells.get_mut(&id)?;
        let callback_id = CallbackId(self.next_callback_id);
        self.next_callback_id += 1;
        cell.callbacks.insert(callback_id, Box::new(callback));
        Some(callback_id)
    }

    pub fn remove_callback(
        &mut self,
        cell_id: ComputeCellId,
        callback_id: CallbackId,
    ) -> Result<(), RemoveCallbackError> {
        let cell = self
            .compute_cells
            .get_mut(&cell_id)
            .ok_or(RemoveCallbackError::NonexistentCell)?;
            
        if cell.callbacks.remove(&callback_id).is_some() {
            Ok(())
        } else {
            Err(RemoveCallbackError::NonexistentCallback)
        }
    }

    fn update_dependents(&mut self, changed_cell: CellId) {
        let mut affected_cells = Vec::new();
        
        match changed_cell {
            CellId::Input(_) => {
                // 收集直接依赖于该输入单元的所有计算单元
                for (&id, cell) in &self.compute_cells {
                    if cell.dependencies.contains(&changed_cell) {
                        affected_cells.push(id);
                    }
                }
            }
            CellId::Compute(id) => {
                // 使用反向依赖关系
                if let Some(cell) = self.compute_cells.get(&id) {
                    affected_cells.extend(&cell.reverse_dependencies);
                }
            }
        }
        
        self.update_compute_cells(affected_cells);
    }

    fn update_compute_cells(&mut self, mut cells_to_update: Vec<ComputeCellId>) {
        let mut visited = std::collections::HashSet::new();
        
        while let Some(id) = cells_to_update.pop() {
            // 避免重复处理
            if !visited.insert(id) {
                continue;
            }
            
            if let Some(cell) = self.compute_cells.get(&id) {
                let dependencies = cell.dependencies.clone();
                let compute_func = &cell.compute_func;
                
                let values: Vec<T> = dependencies
                    .iter()
                    .map(|&dep| self.value(dep).unwrap())
                    .collect();
                
                let new_value = compute_func(&values);
                
                if let Some(cell) = self.compute_cells.get_mut(&id) {
                    let old_value = cell.value;
                    cell.value = new_value;
                    
                    // 如果值发生变化,调用回调函数
                    if old_value != new_value {
                        // 创建回调函数的副本以避免借用冲突
                        let callbacks: Vec<(CallbackId, Box<dyn FnMut(T)>)> = 
                            cell.callbacks.iter_mut()
                                .map(|(&id, callback)| {
                                    (id, std::mem::replace(callback, Box::new(|_| {})))
                                })
                                .collect();
                        
                        // 调用回调函数
                        for (callback_id, mut callback) in callbacks {
                            callback(new_value);
                            cell.callbacks.insert(callback_id, callback);
                        }
                        
                        // 将依赖于此单元的单元添加到更新队列
                        cells_to_update.extend(&cell.reverse_dependencies);
                    }
                }
            }
        }
    }
}

// 使用引用计数的版本
use std::rc::{Rc, Weak};
use std::cell::RefCell;

pub struct RcReactor<T: Copy + PartialEq> {
    cells: Vec<Rc<RefCell<dyn Cell<T>>>>,
}

trait Cell<T> {
    fn value(&self) -> T;
    fn add_dependency(&mut self, dep: Weak<RefCell<dyn Cell<T>>>);
}

struct RcInputCell<T> {
    value: T,
}

struct RcComputeCell<T> {
    dependencies: Vec<Weak<RefCell<dyn Cell<T>>>>,
    compute_func: Box<dyn Fn(&[T]) -> T>,
    value: T,
}

impl<T: Copy + PartialEq> RcReactor<T> {
    pub fn new() -> Self {
        RcReactor {
            cells: Vec::new(),
        }
    }
    
    pub fn create_input(&mut self, initial: T) -> usize {
        let cell = Rc::new(RefCell::new(RcInputCell { value: initial }));
        self.cells.push(cell);
        self.cells.len() - 1
    }
}

错误处理和边界情况

考虑更多边界情况的实现:

rust 复制代码
use std::collections::HashMap;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InputCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ComputeCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct CallbackId(usize);

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CellId {
    Input(InputCellId),
    Compute(ComputeCellId),
}

#[derive(Debug, PartialEq)]
pub enum RemoveCallbackError {
    NonexistentCell,
    NonexistentCallback,
}

#[derive(Debug, PartialEq)]
pub enum ReactorError<T> {
    NonexistentCell,
    DependencyNotFound(CellId),
    CallbackError(RemoveCallbackError),
    ValueError(T),
}

impl<T> From<RemoveCallbackError> for ReactorError<T> {
    fn from(err: RemoveCallbackError) -> Self {
        ReactorError::CallbackError(err)
    }
}

struct InputCell<T> {
    value: T,
}

struct ComputeCell<T> {
    dependencies: Vec<CellId>,
    reverse_dependencies: Vec<ComputeCellId>,
    compute_func: Box<dyn Fn(&[T]) -> T>,
    value: T,
    callbacks: HashMap<CallbackId, Box<dyn FnMut(T)>>,
}

pub struct Reactor<T: Copy + PartialEq> {
    input_cells: HashMap<InputCellId, InputCell<T>>,
    compute_cells: HashMap<ComputeCellId, ComputeCell<T>>,
    next_input_id: usize,
    next_compute_id: usize,
    next_callback_id: usize,
}

impl<T: Copy + PartialEq> Reactor<T> {
    pub fn new() -> Self {
        Reactor {
            input_cells: HashMap::new(),
            compute_cells: HashMap::new(),
            next_input_id: 0,
            next_compute_id: 0,
            next_callback_id: 0,
        }
    }

    pub fn create_input(&mut self, initial: T) -> InputCellId {
        let id = InputCellId(self.next_input_id);
        self.next_input_id += 1;
        self.input_cells.insert(id, InputCell { value: initial });
        id
    }

    pub fn create_compute<F: Fn(&[T]) -> T + 'static>(
        &mut self,
        dependencies: &[CellId],
        compute_func: F,
    ) -> Result<ComputeCellId, CellId> {
        // 检查所有依赖是否存在
        for &dep in dependencies {
            match dep {
                CellId::Input(id) => {
                    if !self.input_cells.contains_key(&id) {
                        return Err(CellId::Input(id));
                    }
                }
                CellId::Compute(id) => {
                    if !self.compute_cells.contains_key(&id) {
                        return Err(CellId::Compute(id));
                    }
                }
            }
        }

        // 计算初始值
        let values: Vec<T> = dependencies
            .iter()
            .map(|&dep| self.value(dep).unwrap())
            .collect();
        let initial_value = compute_func(&values);

        let id = ComputeCellId(self.next_compute_id);
        self.next_compute_id += 1;
        
        // 更新反向依赖关系
        for &dep in dependencies {
            if let CellId::Compute(dep_id) = dep {
                if let Some(dep_cell) = self.compute_cells.get_mut(&dep_id) {
                    if !dep_cell.reverse_dependencies.contains(&id) {
                        dep_cell.reverse_dependencies.push(id);
                    }
                }
            }
        }
        
        let compute_cell = ComputeCell {
            dependencies: dependencies.to_vec(),
            reverse_dependencies: Vec::new(),
            compute_func: Box::new(compute_func),
            value: initial_value,
            callbacks: HashMap::new(),
        };
        
        self.compute_cells.insert(id, compute_cell);
        Ok(id)
    }

    pub fn value(&self, id: CellId) -> Option<T> {
        match id {
            CellId::Input(id) => self.input_cells.get(&id).map(|cell| cell.value),
            CellId::Compute(id) => self.compute_cells.get(&id).map(|cell| cell.value),
        }
    }

    pub fn set_value(&mut self, id: InputCellId, new_value: T) -> bool {
        let cell = match self.input_cells.get_mut(&id) {
            Some(cell) => cell,
            None => return false,
        };

        if cell.value == new_value {
            return true;
        }

        cell.value = new_value;
        self.update_dependents(CellId::Input(id));
        true
    }

    pub fn add_callback<F: FnMut(T) + 'static>(
        &mut self,
        id: ComputeCellId,
        callback: F,
    ) -> Option<CallbackId> {
        let cell = self.compute_cells.get_mut(&id)?;
        let callback_id = CallbackId(self.next_callback_id);
        self.next_callback_id += 1;
        cell.callbacks.insert(callback_id, Box::new(callback));
        Some(callback_id)
    }

    pub fn remove_callback(
        &mut self,
        cell_id: ComputeCellId,
        callback_id: CallbackId,
    ) -> Result<(), RemoveCallbackError> {
        let cell = self
            .compute_cells
            .get_mut(&cell_id)
            .ok_or(RemoveCallbackError::NonexistentCell)?;
            
        if cell.callbacks.remove(&callback_id).is_some() {
            Ok(())
        } else {
            Err(RemoveCallbackError::NonexistentCallback)
        }
    }
    
    // 返回Result的版本
    pub fn set_value_safe(&mut self, id: InputCellId, new_value: T) -> Result<bool, ReactorError<T>> {
        if !self.input_cells.contains_key(&id) {
            return Err(ReactorError::NonexistentCell);
        }
        
        Ok(self.set_value(id, new_value))
    }
    
    pub fn value_safe(&self, id: CellId) -> Result<Option<T>, ReactorError<T>> {
        match self.value(id) {
            Some(value) => Ok(Some(value)),
            None => Err(ReactorError::NonexistentCell),
        }
    }

    fn update_dependents(&mut self, changed_cell: CellId) {
        let mut affected_cells = Vec::new();
        
        match changed_cell {
            CellId::Input(_) => {
                // 收集直接依赖于该输入单元的所有计算单元
                for (&id, cell) in &self.compute_cells {
                    if cell.dependencies.contains(&changed_cell) {
                        affected_cells.push(id);
                    }
                }
            }
            CellId::Compute(id) => {
                // 使用反向依赖关系
                if let Some(cell) = self.compute_cells.get(&id) {
                    affected_cells.extend(&cell.reverse_dependencies);
                }
            }
        }
        
        self.update_compute_cells(affected_cells);
    }

    fn update_compute_cells(&mut self, mut cells_to_update: Vec<ComputeCellId>) {
        let mut visited = std::collections::HashSet::new();
        
        while let Some(id) = cells_to_update.pop() {
            // 避免重复处理
            if !visited.insert(id) {
                continue;
            }
            
            if let Some(cell) = self.compute_cells.get(&id) {
                let dependencies = cell.dependencies.clone();
                let compute_func = &cell.compute_func;
                
                let values: Vec<T> = dependencies
                    .iter()
                    .map(|&dep| self.value(dep).unwrap())
                    .collect();
                
                let new_value = compute_func(&values);
                
                if let Some(cell) = self.compute_cells.get_mut(&id) {
                    let old_value = cell.value;
                    cell.value = new_value;
                    
                    // 如果值发生变化,调用回调函数
                    if old_value != new_value {
                        // 创建临时向量以避免借用冲突
                        let callback_ids: Vec<CallbackId> = cell.callbacks.keys().cloned().collect();
                        let mut callbacks_to_call = Vec::new();
                        
                        for callback_id in callback_ids {
                            if let Some(callback) = cell.callbacks.get_mut(&callback_id) {
                                let callback = std::mem::replace(callback, Box::new(|_| {}));
                                callbacks_to_call.push((callback_id, callback, new_value));
                            }
                        }
                        
                        // 调用回调函数
                        for (callback_id, mut callback, value) in callbacks_to_call {
                            callback(value);
                            cell.callbacks.insert(callback_id, callback);
                        }
                        
                        // 将依赖于此单元的单元添加到更新队列
                        cells_to_update.extend(&cell.reverse_dependencies);
                    }
                }
            }
        }
    }
}

扩展功能

基于基础实现,我们可以添加更多功能:

rust 复制代码
use std::collections::HashMap;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InputCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ComputeCellId(usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct CallbackId(usize);

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CellId {
    Input(InputCellId),
    Compute(ComputeCellId),
}

#[derive(Debug, PartialEq)]
pub enum RemoveCallbackError {
    NonexistentCell,
    NonexistentCallback,
}

struct InputCell<T> {
    value: T,
}

struct ComputeCell<T> {
    dependencies: Vec<CellId>,
    reverse_dependencies: Vec<ComputeCellId>,
    compute_func: Box<dyn Fn(&[T]) -> T>,
    value: T,
    callbacks: HashMap<CallbackId, Box<dyn FnMut(T)>>,
}

pub struct Reactor<T: Copy + PartialEq> {
    input_cells: HashMap<InputCellId, InputCell<T>>,
    compute_cells: HashMap<ComputeCellId, ComputeCell<T>>,
    next_input_id: usize,
    next_compute_id: usize,
    next_callback_id: usize,
}

// 单元信息
pub struct CellInfo {
    pub id: CellId,
    pub dependencies: Vec<CellId>,
    pub reverse_dependencies: Vec<CellId>,
}

impl<T: Copy + PartialEq> Reactor<T> {
    pub fn new() -> Self {
        Reactor {
            input_cells: HashMap::new(),
            compute_cells: HashMap::new(),
            next_input_id: 0,
            next_compute_id: 0,
            next_callback_id: 0,
        }
    }

    pub fn create_input(&mut self, initial: T) -> InputCellId {
        let id = InputCellId(self.next_input_id);
        self.next_input_id += 1;
        self.input_cells.insert(id, InputCell { value: initial });
        id
    }

    pub fn create_compute<F: Fn(&[T]) -> T + 'static>(
        &mut self,
        dependencies: &[CellId],
        compute_func: F,
    ) -> Result<ComputeCellId, CellId> {
        for &dep in dependencies {
            match dep {
                CellId::Input(id) => {
                    if !self.input_cells.contains_key(&id) {
                        return Err(CellId::Input(id));
                    }
                }
                CellId::Compute(id) => {
                    if !self.compute_cells.contains_key(&id) {
                        return Err(CellId::Compute(id));
                    }
                }
            }
        }

        let values: Vec<T> = dependencies
            .iter()
            .map(|&dep| self.value(dep).unwrap())
            .collect();
        let initial_value = compute_func(&values);

        let id = ComputeCellId(self.next_compute_id);
        self.next_compute_id += 1;
        
        for &dep in dependencies {
            if let CellId::Compute(dep_id) = dep {
                if let Some(dep_cell) = self.compute_cells.get_mut(&dep_id) {
                    if !dep_cell.reverse_dependencies.contains(&id) {
                        dep_cell.reverse_dependencies.push(id);
                    }
                }
            }
        }
        
        let compute_cell = ComputeCell {
            dependencies: dependencies.to_vec(),
            reverse_dependencies: Vec::new(),
            compute_func: Box::new(compute_func),
            value: initial_value,
            callbacks: HashMap::new(),
        };
        
        self.compute_cells.insert(id, compute_cell);
        Ok(id)
    }

    pub fn value(&self, id: CellId) -> Option<T> {
        match id {
            CellId::Input(id) => self.input_cells.get(&id).map(|cell| cell.value),
            CellId::Compute(id) => self.compute_cells.get(&id).map(|cell| cell.value),
        }
    }

    pub fn set_value(&mut self, id: InputCellId, new_value: T) -> bool {
        let cell = match self.input_cells.get_mut(&id) {
            Some(cell) => cell,
            None => return false,
        };

        if cell.value == new_value {
            return true;
        }

        cell.value = new_value;
        self.update_dependents(CellId::Input(id));
        true
    }

    pub fn add_callback<F: FnMut(T) + 'static>(
        &mut self,
        id: ComputeCellId,
        callback: F,
    ) -> Option<CallbackId> {
        let cell = self.compute_cells.get_mut(&id)?;
        let callback_id = CallbackId(self.next_callback_id);
        self.next_callback_id += 1;
        cell.callbacks.insert(callback_id, Box::new(callback));
        Some(callback_id)
    }

    pub fn remove_callback(
        &mut self,
        cell_id: ComputeCellId,
        callback_id: CallbackId,
    ) -> Result<(), RemoveCallbackError> {
        let cell = self
            .compute_cells
            .get_mut(&cell_id)
            .ok_or(RemoveCallbackError::NonexistentCell)?;
            
        if cell.callbacks.remove(&callback_id).is_some() {
            Ok(())
        } else {
            Err(RemoveCallbackError::NonexistentCallback)
        }
    }
    
    // 获取单元信息
    pub fn cell_info(&self, id: CellId) -> Option<CellInfo> {
        match id {
            CellId::Input(input_id) => {
                if self.input_cells.contains_key(&input_id) {
                    Some(CellInfo {
                        id,
                        dependencies: vec![],
                        reverse_dependencies: self.compute_cells
                            .iter()
                            .filter(|(_, cell)| cell.dependencies.contains(&id))
                            .map(|(&compute_id, _)| CellId::Compute(compute_id))
                            .collect(),
                    })
                } else {
                    None
                }
            }
            CellId::Compute(compute_id) => {
                if let Some(cell) = self.compute_cells.get(&compute_id) {
                    Some(CellInfo {
                        id,
                        dependencies: cell.dependencies.clone(),
                        reverse_dependencies: cell.reverse_dependencies
                            .iter()
                            .map(|&id| CellId::Compute(id))
                            .collect(),
                    })
                } else {
                    None
                }
            }
        }
    }
    
    // 获取所有单元
    pub fn all_cells(&self) -> Vec<CellId> {
        let mut cells = Vec::new();
        cells.extend(self.input_cells.keys().map(|&id| CellId::Input(id)));
        cells.extend(self.compute_cells.keys().map(|&id| CellId::Compute(id)));
        cells
    }
    
    // 获取依赖图
    pub fn dependency_graph(&self) -> HashMap<CellId, Vec<CellId>> {
        let mut graph = HashMap::new();
        
        // 添加输入单元的依赖(空)
        for &id in self.input_cells.keys() {
            graph.insert(CellId::Input(id), vec![]);
        }
        
        // 添加计算单元的依赖
        for (&id, cell) in &self.compute_cells {
            graph.insert(CellId::Compute(id), cell.dependencies.clone());
        }
        
        graph
    }

    fn update_dependents(&mut self, changed_cell: CellId) {
        let mut affected_cells = Vec::new();
        
        match changed_cell {
            CellId::Input(_) => {
                for (&id, cell) in &self.compute_cells {
                    if cell.dependencies.contains(&changed_cell) {
                        affected_cells.push(id);
                    }
                }
            }
            CellId::Compute(id) => {
                if let Some(cell) = self.compute_cells.get(&id) {
                    affected_cells.extend(&cell.reverse_dependencies);
                }
            }
        }
        
        self.update_compute_cells(affected_cells);
    }

    fn update_compute_cells(&mut self, mut cells_to_update: Vec<ComputeCellId>) {
        let mut visited = std::collections::HashSet::new();
        
        while let Some(id) = cells_to_update.pop() {
            if !visited.insert(id) {
                continue;
            }
            
            if let Some(cell) = self.compute_cells.get(&id) {
                let dependencies = cell.dependencies.clone();
                let compute_func = &cell.compute_func;
                
                let values: Vec<T> = dependencies
                    .iter()
                    .map(|&dep| self.value(dep).unwrap())
                    .collect();
                
                let new_value = compute_func(&values);
                
                if let Some(cell) = self.compute_cells.get_mut(&id) {
                    let old_value = cell.value;
                    cell.value = new_value;
                    
                    if old_value != new_value {
                        let callback_ids: Vec<CallbackId> = cell.callbacks.keys().cloned().collect();
                        let mut callbacks_to_call = Vec::new();
                        
                        for callback_id in callback_ids {
                            if let Some(callback) = cell.callbacks.get_mut(&callback_id) {
                                let callback = std::mem::replace(callback, Box::new(|_| {}));
                                callbacks_to_call.push((callback_id, callback, new_value));
                            }
                        }
                        
                        for (callback_id, mut callback, value) in callbacks_to_call {
                            callback(value);
                            cell.callbacks.insert(callback_id, callback);
                        }
                        
                        cells_to_update.extend(&cell.reverse_dependencies);
                    }
                }
            }
        }
    }
}

// 响应式系统监视器
pub struct ReactorMonitor<'a, T: Copy + PartialEq> {
    reactor: &'a Reactor<T>,
}

impl<'a, T: Copy + PartialEq> ReactorMonitor<'a, T> {
    pub fn new(reactor: &'a Reactor<T>) -> Self {
        ReactorMonitor { reactor }
    }
    
    // 监视单元值的变化
    pub fn watch_value(&self, id: CellId) -> Option<T> {
        self.reactor.value(id)
    }
    
    // 获取单元的依赖信息
    pub fn get_dependencies(&self, id: CellId) -> Option<Vec<CellId>> {
        match id {
            CellId::Input(_) => Some(vec![]),
            CellId::Compute(id) => {
                self.reactor.compute_cells
                    .get(&id)
                    .map(|cell| cell.dependencies.clone())
            }
        }
    }
}

// 便利函数
pub fn create_reactor<T: Copy + PartialEq>() -> Reactor<T> {
    Reactor::new()
}

pub fn link_cells<T: Copy + PartialEq>(
    reactor: &mut Reactor<T>,
    source: CellId,
    target: ComputeCellId,
) -> bool {
    if let Some(cell_info) = reactor.cell_info(source) {
        // 这只是一个示例,实际实现会更复杂
        true
    } else {
        false
    }
}

实际应用场景

响应式编程在实际开发中有以下应用:

  1. 前端框架:ReactJS、Vue.js等现代前端框架的状态管理
  2. 游戏开发:游戏状态管理和UI更新
  3. 数据可视化:实时数据图表和仪表板
  4. 金融系统:实时价格更新和风险计算
  5. 物联网:传感器数据处理和设备控制
  6. 科学计算:数值模拟和数据分析
  7. GUI应用:桌面应用的用户界面更新
  8. 实时系统:需要快速响应数据变化的系统

算法复杂度分析

  1. 时间复杂度

    • 创建单元:O(1)
    • 设置值:O(D),其中D是依赖深度
    • 获取值:O(1)
    • 添加回调:O(1)
  2. 空间复杂度:O(N)

    • 其中N是单元总数,需要存储所有单元及其依赖关系

与其他实现方式的比较

rust 复制代码
// 使用观察者模式的实现
pub trait Observer<T> {
    fn update(&mut self, value: T);
}

pub trait Subject<T> {
    fn attach(&mut self, observer: Box<dyn Observer<T>>);
    fn detach(&mut self, observer: &Box<dyn Observer<T>>);
    fn notify(&self, value: T);
}

// 使用流处理的实现
// [dependencies]
// futures = "0.3"

use futures::stream::Stream;

pub struct ReactiveStream<T> {
    // 基于流的响应式实现
}

// 使用第三方库的实现
// [dependencies]
// rxrust = "1.0"

// 使用RxRust的响应式实现
/*
use rxrust::prelude::*;

pub struct RxReactor<T> {
    // 基于RxRust的实现
}
*/

// 使用宏的实现
macro_rules! reactive_cell {
    ($name:ident, $value:expr) => {
        // 宏实现的响应式单元
    };
}

// 使用函数式响应式编程的实现
pub struct FRPReactor<T> {
    // 函数式响应式编程实现
}

总结

通过 react 练习,我们学到了:

  1. 响应式编程:掌握了响应式编程的核心概念和实现方式
  2. 所有权系统:深入理解了Rust的所有权和借用机制
  3. 闭包处理:学会了存储和调用可变闭包
  4. 数据结构设计:理解了如何设计复杂的数据结构来管理依赖关系
  5. 变化传播:学会了实现值变化的自动传播机制
  6. 类型安全:通过不同的ID类型确保了类型安全

这些技能在实际开发中非常有用,特别是在前端框架、状态管理、实时系统等场景中。响应式编程虽然是一个复杂的概念,但它涉及到了所有权、闭包、数据结构设计、变化检测等许多核心概念,是学习Rust高级编程的良好起点。

通过这个练习,我们也看到了Rust在实现复杂系统方面的强大能力,以及如何用安全且高效的方式实现响应式编程模式。这种结合了安全性和性能的语言特性正是Rust的魅力所在。

相关推荐
Evand J1 小时前
【MATLAB例程】3D雷达-IMU融合定位系统(基于扩展卡尔曼滤波)|雷达观测距离、俯仰角、方向角,IMU包括6维(加速度与角速度)。附下载链接
开发语言·matlab·跟踪·雷达观测·三维定位·ekf滤波
毕设源码柳学姐1 小时前
计算机毕设 java 智慧社区服务系统 SSM 框架社区生活平台 Java 开发的便民服务与互动系统
java·开发语言·生活
陈奕昆1 小时前
n8n实战营Day3:电商订单全流程自动化·需求分析与流程拆解
大数据·开发语言·人工智能·自动化·需求分析·n8n
5***V9331 小时前
MacOS升级ruby版本
开发语言·macos·ruby
Eighteenzi1 小时前
tokio 的理解
rust
星释1 小时前
Rust 练习册 96:Rectangles与几何计算
开发语言·后端·rust
JienDa1 小时前
JienDa聊PHP:电商实战中主流PHP框架的协同策略与架构优化
开发语言·架构·php
星释1 小时前
Rust 练习册 97:Run-Length Encoding 压缩算法
java·linux·rust
Tongfront1 小时前
前端通用submit方法
开发语言·前端·javascript·react