我对铁 rust 的终身保证越来越熟悉,我不确定我想要做的事情是否可能实现.

unwrap时,在最后一次之前的线路上代码死机.编译器正确地理解persons_with_age必须至少活到persons_and_zip_code_city_map.persons岁;但我想向编译器发出信号,我希望它活到persons_and_zip_code_city_map岁,因为它隐含地引用了persons_and_zip_code_city_map.zip_code_city_map.也许我可以用一些零大小的类型来做这件事,或者以某种方式使用生命周期?

这将使此运行时错误变成编译时错误.

use std::collections::HashMap;

#[allow(dead_code)]
#[derive(Clone, Debug)]
struct Person {
    name: String,
    zip_code: u32,
    useless_data: u16,
}

#[allow(dead_code)]
#[derive(Clone, Debug)]
struct PersonWithAge<'a> {
    name: &'a str,
    age: u16,
    zip_code: &'a u32,
}


type ZipcodeCity = HashMap<u32, String>;

struct PersonsAndZipcodes {
    pub persons: Vec<Person>,
    pub zip_code_city_map: ZipcodeCity,
}
    
fn get_persons_with_zip_map(code: u32) -> PersonsAndZipcodes {
    let persons = vec![
        Person { name: "a".to_string(), zip_code: code, useless_data: 10 },
        Person { name: "b".to_string(), zip_code: code, useless_data: 20 },
    ];
    
    let mut zip_code_city_map = HashMap::new();
    zip_code_city_map.insert(code, "street1".to_string());

    return PersonsAndZipcodes {
        persons,
        zip_code_city_map,
    }
}

fn get_persons_ages() -> Vec<u16> {
    vec![30, 40]
}

fn main() {
    // Here I get a vector of Persons (contains a zipcode) and a HashMap from a zipcode to a city.
    // I make sure that every zipcode listed has an entry.
    // While I could have added the city to the Person {}, this would use more memory,
    // since N people can have the same zip_code, which would be added only once to the hashmap.
    let mut persons_and_zip_code_city_map = get_persons_with_zip_map(1);
    let persons = persons_and_zip_code_city_map.persons;
    
    // Another API returns the ages of the persons
    let ages = get_persons_ages();

    assert!(persons.len() == ages.len());
    
    // Here persons_with_age is created attaching the Age to a new object.
    let mut persons_with_age = Vec::new();
    for i in 0..ages.len() {
        persons_with_age.push(
            PersonWithAge {
                name: &persons[i].name,
                age: ages[i],
                zip_code: &persons[i].zip_code,
            }
        );
    }

    println!("{:?}", persons_with_age);

    // Here I get a reference to an specified person
    let this_person = persons_with_age.get(0).unwrap();

    // persons_and_zip_code_city_map is updated
    persons_and_zip_code_city_map = get_persons_with_zip_map(2);

    // Now I try to access the zipcode of `this_person` I have.
    // My logic guarantees that `persons_and_zip_code_city_map.zip_code_city_map` would
    // have this zipcode at the time I acquired `this_person`, but now it has been updated
    // and the zipcode doesn't exist anymore.
    // If I had assigned `persons.get(0).unwrap()` to `this_person`, the compiler catch this
    // mistake, but it doesn't because I'm using `persons_with_age`.
    // Is it possible to perhaps bind the lifetime of `persons_with_age` with `persons_and_zip_code_city_map`?
    let this_person_city: String = persons_and_zip_code_city_map.zip_code_city_map.get(&this_person.zip_code).cloned().unwrap();

    println!("{:?} {:?}", this_person, this_person_city);
}

Playground

推荐答案

您要将persons数组移出一个局部变量,然后borrow 另一个变量:

let persons = persons_and_zip_code_city_map.persons;

这就是允许覆盖persons_and_zip_code_city_map的原因,它被部分移动,但不被borrow .

解决方案是borrow 价值,而不是:

let persons = &persons_and_zip_code_city_map.persons;

那么,当你从persons借钱时,你实际上是从persons_and_zip_code_city_map借钱,所以这是不可修改的.

您可以通过将persons成员设置为私有并编写访问器函数来禁止移动该成员:

impl PersonsAndZipcodes {
    pub fn persons(&self) -> &[Person] {
        &self.persons
    }
}

您甚至可以将此类型嵌套到内部模块中,以便您的主模块无法访问其私有部分.

另一种禁止移出成员变量的方法是实现Drop:

impl Drop for PersonsAndZipcodes {
    fn drop(&mut self) {}
}

但在我看来,仅仅为了避免将其成员迁出而实施Drop似乎有点老土.

Rust相关问答推荐

在一个tauri协议处理程序中调用一个rectuc函数的推荐技术是什么?

使用模块中的所有模块,但不包括特定模块

获取字符串切片(&;str)上的切片([ia..ib])返回字符串

新创建的变量的绑定生存期

有没有办法在Rust中配置常量变量的值?

像这样的铁 rust 图案除了‘选项’之外,还有其他 Select 吗?

铁 rust 中的泛型:不能将`<;T作为添加>;::Output`除以`{Float}`

告诉Rust编译器返回值不包含构造函数中提供的引用

无法定义名为&new&的关联函数,该函数的第一个参数不是self

为什么基于高山Linux的Docker镜像不能在绝对路径下找到要执行的命令?

是否可以在不切换到下一个位置的情况下获得迭代器值:

如何在嵌套的泛型 struct 中调用泛型方法?

try 实现线程安全的缓存

为什么需要静态生命周期以及在处理 Rust 迭代器时如何缩小它?

如何在Rust中使用Serde创建一个自定义的反序列化器来处理带有内部标记的枚举

Rust 中的自动取消引用是如何工作的?

rust tokio::spawn 在 mutexguard 之后等待

发生移动是因为 `data` 的类型为 `Vec`,它没有实现 `Copy` 特性

有没有办法隐藏类型定义?

有没有办法在 Rust 中对 BigInt 进行正确的位移?