【问题标题】:Is it possible to borrow parts of a struct as mutable and other parts as immutable?是否可以将结构的部分借用为可变的,而将其他部分借用为不可变的?
【发布时间】:2018-02-02 04:09:49
【问题描述】:

如果结构的字段是私有的,是否可以将结构的一部分借用为可变的,而将另一部分借用为不可变的。

fn main() {
    let mut ecs = EntityComponentSystem::new();

    for e_id in ecs.get_entities_with_component::<Velocity>().unwrap() {
           let components = ecs.get_mut_components(e_id);
           ...
}

impl EntityComponentSystem {
    ...
    pub fn get_entities_with_component<K: Key>(&self) -> Option<&HashSet<u64>> {
        self.entities_with_components.get(&TypeId::of::<K>())
    }

    pub fn get_mut_components(&mut self, entity_id: u64) -> &mut TypeMap {
        let entity = self.entities.get_mut(&entity_id).unwrap();
        &mut entity.components
    }
}

pub struct EntityComponentSystem {
    entities: HashMap<u64, Entity>,                     <------- I would like to modify this.
    entities_with_components: HashMap<TypeId, HashSet<u64>>,   <---- while reading from this!
}

编译器给了我:

error[E0502]: cannot borrow `*ecs` as mutable because it is also borrowed as immutable
  --> physics.rs:19:26
   |
18 |     for e_id in ecs.get_entities_with_component::<Velocity>() {
   |                 --- immutable borrow occurs here
19 |         let components = ecs.get_mut_components(*e_id);
   |                          ^^^ mutable borrow occurs here
...
26 |     }
   |     - immutable borrow ends here

我不明白的是,在我们基本上返回了 entities_with_components 字段的一部分之后,get_entities_with_component 中的 &amp;self 引用仍然是如何被借用的。

不应该只借那部分吗?有什么办法可以强制执行吗?

【问题讨论】:

    标签: rust borrow-checker


    【解决方案1】:

    不,函数不能返回对结构的一部分的引用并让结构部分借用。

    但是你可以像这样返回不可变和可变借用的元组

    #[derive(Debug)]
    struct AB(u32, u32);
    
    impl AB {
        fn borrow_parts(&mut self) -> (&u32, &mut u32) {
            (&self.0, &mut self.1)
        }
    }
    
    fn main() {
        let mut ab = AB(0, 2);
        {
            let (a, b) = ab.borrow_parts();
            *b = *a;
        }
        println!("{:?}", ab);
    }
    

    【讨论】:

    • 我不知道在 OP 的情况下你会怎么做,因为他们在循环外进行一次不可变借用,而在循环内多次进行可变借用。
    • @interjay,如果为HashMap&lt;TypedId, HashSet&lt;u64&gt;&gt; 或某些包装类型实现get_mut_components,则不需要多次可变借用,可变引用将作为结果的一部分返回borrow_parts.
    【解决方案2】:

    你只能借用 entire 结构作为不可变或可变结构,没有只借用它的一部分的概念。当这成为问题时,您可以以RefCell 的形式使用interior mutability

    pub struct EntityComponentSystem {
        entities: RefCell<HashMap<u64, Entity>>,
        entities_with_components: HashMap<TypeId, HashSet<u64>>,
    }
    

    现在您可以将整个结构体借用为不可变结构,并将RefCell 的内容独立地借用为可变结构:

    pub fn get_mut_components(&self, entity_id: u64) -> &mut TypeMap {
        let mut entities = self.entities.borrow_mut();
        let entity = entities.get_mut(&entity_id).unwrap();
        &mut entity.components
    }
    

    【讨论】:

    • "你只能将整个结构体借用为不可变或可变的,没有只借用它的一部分的概念。"要学究,是的。您可以对结构进行部分借用,但这不适用于操作,因为这些字段是私有的。这是一个例子:play.rust-lang.org/…
    猜你喜欢
    • 2016-05-02
    • 1970-01-01
    • 2015-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多