我有一个用户的域模型,其中存储了original个用户状态和current个用户状态.如果当前状态的属性不匹配原始—它需要在数据库中更新并包含在SQL查询中.

for each 属性创建类似的比较方法变得重复,我想知道,有没有一种方法可以用一些通用的共享方法来替换这个比较方法?

注意:如果实现起来更简单,可以将原始的更改为非可选的.它用于区分刚创建的模型的插入和更新SQL操作

Playground

#[derive(Debug, Clone)]
struct UserProps {
    pub age: i32,
    pub name: String,
}
struct User {
    pub original: Option<UserProps>,
    pub current: UserProps,
}
impl User {
    // creating similar function for each property is burthersome
    // is there a way to create a generic one?
    pub fn age_changed(&self) -> bool {
        self.original
            .as_ref()
            .map_or(true, |val| val.age != self.current.age)
    }

    pub fn name_changed(&self) -> bool {
        self.original
            .as_ref()
            .map_or(true, |val| val.name != self.current.name)
    }
}

fn x() {
    let props = UserProps {
        age: 12,
        name: "x".to_owned(),
    };

    let mut user = User {
        original: Some(props.clone()),
        current: props.clone(),
    };

    user.current.age = 22;

    assert!(user.age_changed());
    if user.age_changed() {
        
        // add property to sql query update operation
    }
}

在JavaScript中,我会这样做:

propertyChanged(propName: string): boolean {
  if (this.original === undefined){
     return true
  }

  return this.original[propName] !== this.current[propName]
}

推荐答案

一个宏来拯救:

macro_rules! generate_prop_changed {
    ( $( $method:ident => $prop:ident; )*  ) => {
        $(
            pub fn $method(&self) -> bool {
                self.original
                    .as_ref()
                    .map_or(true, |val| val.$prop == self.current.$prop)
            }
        )*
    };
}

impl User {
    generate_prop_changed! {
        age_changed => age;
        name_changed => name;
    }
}

如果你想玩Pro—Land,试试:

  1. 不再需要提供方法名称(提示:paste).
  2. 通过用宏包装 struct 声明,消除了提供字段名称的需要.
  3. 最困难的是:为它创造derive macro.

Rust相关问答推荐

有条件默认实现

无需通过ASIO输入音频,并使用cpal进行反馈示例

为什么函数不接受选项T参数的所有权?

如何从polars DataFrame中获取一个列作为Option String?<>

如何装箱生命周期相关联的两个对象?

在泛型 struct 的字段声明中访问关联的Conant

何时可以在Rust中退出异步操作?

具有对同一类型的另一个实例的可变引用的

我们能确定Rust会优化掉Clone()吗?如果它会立即掉落?

在铁 rust 中,如何一次只引用几件事中的一件?

应为关联类型,找到类型参数

在运行特定测试时,如何 suppress cargo test 的空输出?

为什么我需要 to_string 函数的参考?

为什么编译器看不到这个 `From` impl?

Rust 如何将链表推到前面?

为什么数组不像向量那样在 for 块之后移动?

LinkedList::drain_filter::drop 中 DropGuard 的作用是什么?

Rust 跨同一文件夹中文件的可见性

TinyVec 如何与 Vec 大小相同?

需要括号的宏调用中的不必要的括号警告 - 这是编写宏的糟糕方法吗?