我尝试找到两个流(由迭代器表示)的差异以进行后续分析,下面的代码工作正常,但是在update_v?函数中更新值时看起来有点难看并且容易出错(复制粘贴!)。假设来源很重要,有什么办法可以概括它?

struct Data {};

struct S {
    v1: Option<Data>,
    v2: Option<Data>
}

...

fn update_v1(diffs: &mut HashMap<u64, Data>, key: u64, data: Data) {
    match diffs.entry(key) {
        Entry::Vacant(v) => {
            let variant = S {
                v1: Some(data),
                v2: None
            };
            v.insert(variant);
        },
        Entry::Occupied(e) => {
            let new_variant = Some(data);
            if e.get().v2 == new_variant {
                e.remove();
            } else {
                let existing = e.into_mut();
                existing.v1 = new_variant;
            }
        }
    }
}

fn update_v2(diffs: &mut HashMap<u64, Data>, key: u64, data: Data) {
    match diffs.entry(key) {
        Entry::Vacant(v) => {
            let variant = S {
                v2: Some(data),
                v1: None
            };
            v.insert(variant);
        },
        Entry::Occupied(e) => {
            let new_variant = Some(data);
            if e.get().v1 == new_variant {
                e.remove();
            } else {
                let existing = e.into_mut();
                existing.v2 = new_variant;
            }
        }
    }
}

最佳答案

代替为每个字段编写一个函数,而是接收一对Fn作为参数:

  • fn(&S) -> Option<Data>,可以用来代替这种情况
    if e.get().v1 == new_variant { /* ... */ }
    

    有了这个
    if getter(e.get()) == new_variant { /* ... */ }
    
  • fn(&mut S, Option<Data>) -> (),它将替换
    existing.v2 = new_variant;
    


    setter(&mut existing, new_variant);
    

  • 然后,在调用站点上,您会传递几个lambda
  • setter/getter :|d| d.v1
  • 二传手:|s, d| s.v2 = d

  • 或反之亦然。

    而且,如果要保留update_v1update_v2函数名称,只需将它们作为包装器写入到此新的通用函数即可,该函数会自动传递适当的lambda。

    关于rust - 如何概括对结构域的访问?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47049658/

    10-10 06:51