在惯用Rust中实现容器元素关系的正确方法

时间:2017-06-17 17:32:55

标签: rust borrow-checker

我知道为什么Rust不喜欢我的代码。但是,我不知道什么是习惯性的Rust解决问题的方法。

我是一名C#程序员,虽然我觉得我理解Rust系统,但我认为我的#34;以及#34;处理一些问题的方法根本不适用于Rust。

此代码重现了我遇到的问题,它可能看起来不像是惯用的Rust(或者它在C#中看起来也不好看):

//a "global" container for the elements and some extra data
struct Container {
    elements: Vec<Element>,
    global_contextual_data: i32,
    //... more contextual data fields
}

impl Container {
   //this just calculates whatever I need based on the contextual data
   fn calculate_contextual_data(&self) -> i32 {
       //This function will end up using the elements vector and the other fields as well, 
       //and will do some wacky maths with it. 
       //That's why I currently have the elements stored in the container
   }
}

struct Element {
    element_data: i32,
    //other fields
}

impl Element {
    //I need to take a mutable reference to update element_data, 
    //and a reference to the container to calculate something that needs 
    //this global contextual data... including the other elements, as previously stated
    fn update_element_data(&mut self, some_data: i32, container: &Container) {
        self.element_data *= some_data + container.calculate_contextual_data() //do whatever maths I need
    }
}


fn main(){

    //let it be mutable so I can assign the elements later
    let mut container = Container {
        elements: vec![],
        global_contextual_data: 1
    };

    //build a vector of elements
    let elements = vec![
        Element {
            element_data: 5
        },
        Element {
            element_data: 7
        }
    ];

    //this works
    container.elements = elements;

    //and this works, but container is now borrowed as mutable
    for elem in container.elements.iter_mut() {
        elem.element_data += 1; //and while this works
        let some_data = 2;

        //i can't borrow it as immutable here and pass to the other function
        elem.update_element_data(some_data, &container); 
    }
}

我理解为什么elem.update_element_data(some_data, &container);无法工作:当我致电iter_mut时,我已经将其借用为可变的。也许每个元素都应该引用容器?但是,我不会有更多机会打破借阅检查吗?

我认为不可能将我的旧方法带入这个新系统。也许我需要改写整个事情。有人能指出我正确的方向吗?我刚刚开始使用Rust编程,虽然所有权系统对我有些意义,但我应该编写的代码&#34;围绕&#34;它仍然不是那么清楚。

1 个答案:

答案 0 :(得分:0)

我遇到了这个问题: What's the Rust way to modify a structure within nested loops?让我深入了解了我的问题。

我重新审视了这个问题,并通过借用写入和读取来同时将问题归结为向量的共享。这只是Rust禁止的。我不想使用unsafe绕过借阅检查器。我想知道,我应该复制多少数据?

我的Element,实际上是游戏的实体(我模拟点击游戏)具有可变和不可变的属性,我分崩离析。

struct Entity {
    type: EntityType,
    starting_price: f64, 
    ...
    ...
    status: Cell<EntityStatus>
}

每次我需要更改实体的状态时,我都需要在get字段上调用setstatus方法。 EntityStatus派生Clone, Copy

我甚至可以直接将字段放在结构上,并将它们全部设为Cell,但是使用它们会很麻烦(很多调用getset ),所以我采取了更美观的方法。

通过允许自己复制status,编辑并set它,我可以不可变地借用数组两次(.iter()而不是.iter_mut())。

我担心由于复制会导致性能下降,但实际上,一旦我使用opt-level=3进行编译,它就会非常好。如果它有问题,我可能会将字段更改为Cell或提出另一种方法。