gpt4 book ai didi

rust - Rust-缓存某些不可变数据 View 的惯用方式

转载 作者:行者123 更新时间:2023-12-03 11:37:01 25 4
gpt4 key购买 nike

这是一个简单的结构World的一些示例代码,该结构包含一个Object的向量,为此每个Object分配了一个类别。

#[derive(PartialEq, Debug)]
enum Category {
A, B, C, D
}

#[derive(Debug)]
struct Object {
pub someData: f64,
pub category: Category
//...
}

struct World {
pub objects: Vec<Object>,
//...
}

impl World {
pub fn new(objects: Vec<Object>) -> Self {
World { objects }
}

pub fn getObjectsOfCategoryA(&self) -> Vec<&Object> {
self.objects.iter().filter(|x| x.category == Category::A).collect()
}
}
World还为用户提供了查询特别是类别A的对象的能力。
但是,如果我想频繁调用 getObjectsOfCategoryA(),出于性能原因,我想缓存该函数的结果该怎么办?理想情况下,此缓存对于 getObjectsOfCategoryA()的任何调用者都应该是不透明的。
让我们添加一个限制,即在创建 objects之后,保证 World不被突变。
(我不知道如何表达对Rust的这种限制,但我们稍后会再讨论)。 Object不会派生 CopyClone,因此我们不能仅创建一个新的克隆对象矢量作为我们的缓存矢量。
一种方法是使用 Arc:
struct World {
objects: Vec<Arc<Object>>,
objectsOfCategoryA: Vec<Arc<Object>>
}

impl World {
pub fn new(objects: Vec<Object>) -> Self {
let arcObjects: Vec<Arc<Object>> = objects.into_iter()
.map(|x| Arc::new(x)).collect();
let objectsOfCategoryA = arcObjects.iter().filter(|x| x.category == Category::A)
.map(|x| x.clone()).collect();
World { objects: arcObjects, objectsOfCategoryA }
}

pub fn getObjectsOfCategoryA(&self) -> &Vec<Arc<Object>> {
&self.objectsOfCategoryA
}
}
这使我感到不理想,因为:
  • 我们需要更改主要objects向量
  • 的存储模式
  • 这并不直观地向代码读者表明objectsOfCategoryA只是objects的 View
  • 如果偶然更改了objects,则此操作将自动失败。理想情况下,如果在构造了objects之后有任何尝试使World发生突变的情况,我希望产生编译错误。

  • 如果有某种方式让 objectsOfCategoryA成为对我来说“正确”的 Vec<&Object>,但是根据我的研究,看来这是不可能的。
    我是Rust的新手,所以很有可能我从OOP的角度来看了这一点。谁能指出一种惯用的方式来实现这种缓存?

    最佳答案

    您希望ObjectsCategory::A缓存可以是Vec<&Object>类型。这不是惯用语言,需要修补才能起作用。下一个最好的事情是类型为Option<Vec<&Object>>的延迟评估的缓存。如果世界被声明为

    struct World<'a> {
    objects: Vec<Object>,
    category_a: Option<Vec<&'a Object>>,
    //...
    }
    您可以将其初始化为 World { objects, None },然后在需要获取 Category::A的对象时,可以遍历 Vec并填充缓存字段(注意:这需要mut引用,可以通过内部可变性避免使用)。
    pub fn getObjectsOfCategoryA(&'a mut self) -> &'a Vec<&Object> {
    if self.category_a.is_none() {
    self.category_a = Some(self.objects.iter().filter(|x| x.category == Category::A).collect());
    }
    self.category_a.as_ref().unwrap()
    }
    您甚至可以通过包装World的 objects.push()来允许对象突变,以正确更新缓存,就像这样
    // impl World {
    // ...
    pub fn push_inner(&'a mut self, obj:Object) {
    self.objects.push(obj);
    if self.objects.last().unwrap().category == Category::A {
    if let Some(category_a) = &mut self.category_a {
    category_a.push(self.objects.last().unwrap())
    }
    }
    }
    Here是用于测试此代码的完整代码的链接。

    关于rust - Rust-缓存某些不可变数据 View 的惯用方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63642642/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com