我正在为一个 struct 体写一个方法,它的成员是Vec.我想写的函数remove_thing应该引用Vec中的一个元素并删除它,其余部分留在原位.

我得到了一个借位判断器错误,我不能borrow Vec作为可变的,因为我有一个借位的元素是不可变的.我的期望是,仍然有一个有效的方式来表达这一点,因为我实际上并没有改变内部元素,只是改变包含Vec.但我可能错了.

下面是一个简短的复制:

struct Thing {
    name: String,
    data: String,
}

struct HasSomeThings {
    things: Vec<Thing>,
}

impl HasSomeThings {
    fn thing_by_name(&self, name: &str) -> Option<&Thing> {
        for t in self.things.iter() {
            if t.name == name {
                return Some(&t);
            }
        }
        None
    }

    // Is it impossible to implement this function? 
    // It seems having a reference to a Thing in the vector prevents 
    // you from removing it from that vector.    
    fn remove_thing(&mut self, thing: &Thing) {
        self.things.retain(|t| t.name != thing.name);
    }
}

fn main() {
    // Imagine this comes from reading a file somewhere
    let mut some_things = HasSomeThings {
        things: vec![
            Thing { name: "one".to_string(), data: "one data".to_string() },
            Thing { name: "two".to_string(), data: "two data".to_string() },
            Thing { name: "three".to_string(), data: "three data".to_string() },
        ]
    };
    
    // Imagine this comes from user input
    let name = "one";
    let one_thing = some_things.thing_by_name(name).unwrap();
    println!("{}", one_thing.data);
    
    some_things.remove_thing(one_thing);
}

Rust Playground Link

我看到的错误是:

Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `some_things` as mutable because it is also borrowed as immutable
  --> src/main.rs:44:5
   |
41 |     let one_thing = some_things.thing_by_name(name).unwrap();
   |                     ----------- immutable borrow occurs here
...
44 |     some_things.remove_thing(one_thing);
   |     ^^^^^^^^^^^^------------^^^^^^^^^^^
   |     |           |
   |     |           immutable borrow later used by call
   |     mutable borrow occurs here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` (bin "playground") due to 1 previous error

有没有一些技巧可以实现remove_thing函数?或者,有没有合理的方法来重组我的代码,以便我可以使用引用Vec中的元素,然后再删除它?我是否只需要从头开始重建整个HasSomeThings实例?

推荐答案

这是一个罕见的情况下,原始指针可以使用而不涉及任何不安全的代码:

// References coerce into pointers, so no other code needs to change.
fn remove_thing(&mut self, thing: *const Thing) {
    self.things.retain(|t| !std::ptr::addr_eq(t, thing));
}

playground

Rust相关问答推荐

使用Clap时如何将String作为Into Str参数传递?

无法理解铁 rust &S错误处理

在析构赋值中使用一些现有绑定

如何定义实现同名但返回类型不同的 struct 的函数

在0..1之间将U64转换为F64

如何使用Actix Web for Rust高效地为大文件服务

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

使用Rust WASM读取文件

返回Result<;(),框<;dyn错误>>;工作

为什么我必须使用 PhantomData?在这种情况下它在做什么?

在 Rust 中,为什么 10 个字符的字符串的 size_of_val() 返回 24 个字节?

在 Rust 中,在第一个空格上分割字符串一次

在Rust中实现Trie数据 struct 的更好方式

了解 Rust 闭包:为什么它们持续持有可变引用?

在运行时在 Rust 中加载字体

Rust 函数指针似乎被borrow 判断器视为有状态的

当 T 不是副本时,为什么取消引用 Box 不会抱怨移出共享引用?

为什么在 rust 中删除 vec 之前应该删除元素

如何在 Rust Polars 中可靠地连接 LazyFrames

在 Rust 中组合特征的不同方法是否等效?