Rust变更检测库change-detection的使用,高效追踪数据结构变化与状态差异

Rust变更检测库change-detection的使用,高效追踪数据结构变化与状态差异

功能特性

自动生成静态文件的变更检测指令。

使用方法

添加依赖到Cargo.toml

[dependencies]
change-detection = "1.2"

基础使用示例

在build.rs中添加调用:

use change_detection::ChangeDetection;

fn main() {
    ChangeDetection::path("src/hello.c").generate();
}

这等同于直接写:

fn main() {
    println!("cargo:rerun-if-changed=src/hello.c");
}

目录监控示例

监控整个目录的变化:

use change_detection::ChangeDetection;

fn main() {
    ChangeDetection::path("static").generate();
}

多路径监控示例

use change_detection::ChangeDetection;

fn main() {
    ChangeDetection::path("static")
        .path("another_path")
        .path("build.rs")
        .generate();
}

使用glob模式过滤

#[cfg(features = "glob")]
use change_detection::{path_matchers::glob, ChangeDetection};

fn main() {
    #[cfg(features = "glob")]
    ChangeDetection::exclude(glob("another_path/**/*.tmp").unwrap())
        .path("static")
        .path("another_path")
        .path("build.rs")
        .generate();
}

完整示例demo

以下是一个完整的build.rs示例,展示了如何使用change-detection库来监控项目中的多个目录和文件:

// build.rs
use change_detection::ChangeDetection;

fn main() {
    // 监控src目录的所有文件
    ChangeDetection::path("src")
        // 监控assets目录
        .path("assets")
        // 监控特定的配置文件
        .path("config.toml")
        // 监控build.rs本身
        .path("build.rs")
        // 生成变更检测指令
        .generate();
    
    // 其他构建任务...
    println!("cargo:rerun-if-changed=build.rs");
}

对于更复杂的过滤需求,可以使用path-matchers功能:

// build.rs
#[cfg(features = "glob")]
use change_detection::{path_matchers::glob, ChangeDetection};

fn main() {
    #[cfg(features = "glob")]
    ChangeDetection::exclude(glob("target/**").unwrap())  // 排除target目录
        .exclude(glob("**/*.tmp").unwrap())              // 排除所有临时文件
        .path("src")
        .path("assets")
        .generate();
    
    // 其他构建任务...
}

查看生成的变更检测指令

你可以使用以下命令查看实际生成的变更检测指令:

find . -name output | xargs cat

许可证

双重许可:MIT或UNLICENSE。


1 回复

Rust变更检测库change-detection使用指南

change-detection是一个用于高效追踪数据结构变化和状态差异的Rust库,特别适合需要监控状态变更的场景。

基本概念

该库提供了两种主要的变更检测机制:

  • ChangeDetection: 简单高效的变更检测
  • DeepChangeDetection: 深度变更检测,可以递归检查嵌套结构

安装

在Cargo.toml中添加依赖:

[dependencies]
change-detection = "0.1"

基本使用

1. 简单变更检测

use change_detection::ChangeDetection;

#[derive(ChangeDetection)]
struct MyStruct {
    field1: String,
    field2: i32,
}

fn main() {
    let mut my_data = MyStruct {
        field1: "Hello".to_string(),
        field2: 42,
    };
    
    // 检查是否有变化
    println!("Changed? {}", my_data.changed()); // false
    
    // 修改字段
    my_data.field1 = "World".to_string();
    
    // 再次检查
    println!("Changed? {}", my_data.changed()); // true
    
    // 重置变更状态
    my_data.reset_change();
    println!("Changed? {}", my_data.changed()); // false
}

2. 深度变更检测

use change_detection::DeepChangeDetection;

#[derive(DeepChangeDetection)]
struct NestedStruct {
    inner_field: String,
}

#[derive(DeepChangeDetection)]
struct Container {
    nested: NestedStruct,
    value: i32,
}

fn main() {
    let mut container = Container {
        nested: NestedStruct {
            inner_field: "Initial".to_string(),
        },
        value: 100,
    };
    
    println!("Changed? {}", container.deep_changed()); // false
    
    // 修改嵌套字段
    container.nested.inner_field = "Modified".to_string();
    
    println!("Changed? {}", container.deep_changed()); // true
}

高级用法

1. 自定义变更检测

use change_detection::{ChangeDetection, ChangeTracker};

#[derive(ChangeDetection)]
struct CustomStruct {
    #[change_detection(ignore)] // 忽略此字段的变更检测
    ignored_field: String,
    
    #[change_detection(track)] // 显式标记需要跟踪
    tracked_field: i32,
    
    // 默认会跟踪所有字段,除非显式忽略
    another_field: bool,
}

#[derive(ChangeDetection)]
struct WithCustomTracker {
    #[change_detection(tracker = "MyCustomTracker")] // 使用自定义跟踪器
    custom_field: String,
}

struct MyCustomTracker;
impl ChangeTracker for MyCustomTracker {
    // 实现自定义跟踪逻辑
}

2. 变更通知

use change_detection::{ChangeDetection, ChangeListener};

#[derive(ChangeDetection)]
struct ObservableStruct {
    data: String,
}

fn main() {
    let mut observable = ObservableStruct {
        data: "Initial".to_string(),
    };
    
    // 添加变更监听器
    let listener = ChangeListener::new(&observable, || {
        println!("Data has changed!");
    });
    
    // 修改数据会触发监听器
    observable.data = "New value".to_string();
}

性能考虑

  1. ChangeDetection适合简单结构,开销很小
  2. DeepChangeDetection会递归检查所有嵌套字段,对复杂结构可能有性能影响
  3. 使用#[change_detection(ignore)]可以优化不需要检测的字段

实际应用场景

  1. UI状态管理
  2. 游戏对象状态跟踪
  3. 配置变更监控
  4. 数据持久化触发条件

这个库通过派生宏简化了变更检测的实现,使得开发者可以专注于业务逻辑而不是手动跟踪状态变化。

完整示例

以下是一个结合了简单变更检测和深度变更检测的完整示例:

use change_detection::{ChangeDetection, DeepChangeDetection};

// 简单变更检测示例
#[derive(ChangeDetection, Debug)]
struct UserProfile {
    username: String,
    age: u8,
    #[change_detection(ignore)]
    last_login: String, // 忽略此字段的变更检测
}

// 深度变更检测示例
#[derive(DeepChangeDetection, Debug)]
struct Address {
    street: String,
    city: String,
}

#[derive(DeepChangeDetection, Debug)]
struct UserDetails {
    profile: UserProfile,
    address: Address,
    is_verified: bool,
}

fn main() {
    // 简单变更检测演示
    let mut profile = UserProfile {
        username: "john_doe".to_string(),
        age: 30,
        last_login: "2023-01-01".to_string(),
    };

    println!("Profile changed? {}", profile.changed()); // false
    
    profile.age = 31;
    println!("After age change - changed? {}", profile.changed()); // true
    
    profile.reset_change();
    profile.last_login = "2023-02-01".to_string();
    println!("After ignored field change - changed? {}", profile.changed()); // false

    // 深度变更检测演示
    let mut user = UserDetails {
        profile: UserProfile {
            username: "jane_doe".to_string(),
            age: 28,
            last_login: "2023-01-15".to_string(),
        },
        address: Address {
            street: "123 Main St".to_string(),
            city: "New York".to_string(),
        },
        is_verified: false,
    };

    println!("User details changed? {}", user.deep_changed()); // false
    
    // 修改嵌套结构
    user.address.city = "Boston".to_string();
    println!("After address change - changed? {}", user.deep_changed()); // true
    
    // 重置变更状态
    user.reset_change();
    println!("After reset - changed? {}", user.deep_changed()); // false
    
    // 修改忽略的字段不会触发变更
    user.profile.last_login = "2023-02-15".to_string();
    println!("After ignored field change - changed? {}", user.deep_changed()); // false
}

这个完整示例展示了:

  1. 简单结构如何使用ChangeDetection
  2. 嵌套结构如何使用DeepChangeDetection
  3. 如何通过#[change_detection(ignore)]忽略特定字段
  4. 变更检测和重置的基本操作

示例中的注释解释了每个关键步骤的行为,可以帮助理解变更检测的工作机制。

回到顶部