rust 你能找到一个向量的元素并改变它吗?

eyh26e7m  于 2023-05-17  发布在  其他
关注(0)|答案(1)|浏览(77)

假设我有那些结构体(没有花哨的指针,一切都是可复制的)

#[derive(Debug, Copy, Clone)]
struct Item {
    id: u32,
    pub value: u32
}

我可以创建一个struct来保存这样的项目的vec:

#[derive(Debug)]
struct Container {
    next_id: u32,
    items: Vec<Item>
}

如果你知道确切的位置,添加元素和更改它们是相当容易的:

impl Container {
    fn new() -> Container {
        Container {
            next_id: 0,
            items: vec!()
        }
    }

    fn add(&mut self) -> u32 {
        let id = self.next_id;
        self.items.push(Item {
            id: self.next_id,
            value: 0
        });
        self.next_id = self.next_id + 1;
        id
    }

    fn lookup(&mut self, id: u32) -> Option<&Item> {
        self.items.iter().find(|item| item.id == id)
    }

    fn change_first(&mut self, new_value: u32) {
        if self.items.len() < 0 {
            panic!("No item to change");
        }
        self.items[0].value = new_value;
    }
}

这使得这样的测试通过:

#[test]
    fn can_change_first() {
        let mut c = Container::new();
        assert_eq!(c.add(), 0);
        c.change_first(22);
        assert_eq!(c.lookup(0).unwrap().value, 22);
    }

但是,假设我想查找和元素并找到它.我不想直接公开items vec,但建议使用一个API:

#[test]
    fn can_lookup_and_change() {
        let mut c = Container::new();
        assert_eq!(c.add(), 0);
        c.change_at(0, 22);
        assert_eq!(c.lookup(0).unwrap().value, 22);
    }

change_at的简单实现是:

fn change_at(&mut self, id: u32, new_value: u32) {
        let lookup = self.lookup(id);
        match lookup {
            Some(item) => {
                item.value = new_value;
            }
            None => {
                // ...
            }
        }
    }

但是,编译器不接受它,并给出错误:

Compiling web v0.1.0 (/home/phtrivier/perso/prj/wirth/dom-web)
error[E0594]: cannot assign to `item.value`, which is behind a `&` reference
   --> redacted/src/lib.rs:170:17
    |
169 |             Some(item) => {
    |                  ---- consider changing this binding's type to be: `&mut Item`
170 |                 item.value = new_value;
    |                 ^^^^^^^^^^^^^^^^^^^^^^ `item` is a `&` reference, so the data it refers to cannot be written

For more information about this error, try `rustc --explain E0594`.

我不明白错误是否在lookup端(是否有不同的方法来查找项目,使他们静音?)或change_at端(这是模式匹配的正确方法吗?)

xsuvu9jc

xsuvu9jc1#

您可以添加一个lookup_mut方法。这将用iter_mut替换iter

fn lookup_mut(&mut self, id: u32) -> Option<&mut Item> {
    self.items.iter_mut().find(|item| item.id == id)
}

然后在需要可变引用时使用它。

let lookup = self.lookup_mut(id);

相关问题