Как Rust хранит заимствованные значения в коллекции? - PullRequest
0 голосов
/ 24 апреля 2018

В этом:

#[derive(Debug)]
struct Person {
    name: String,
}

fn main() {
    let mut persons = Vec::<Person>::with_capacity(3);
    let mut personrefs = Vec::<&Person>::with_capacity(persons.capacity());
    for x in 0..persons.capacity() {
        let person = Person {
            name: format!("Alice-{}", x),
        };
        personrefs.push(&person);
        persons.push(person);
    }
    println!("persons are {:#?}", persons);
}

Я вроде понимаю, почему Rust не позволяет нажимать &person, но как Rust может решить эту проблему?

У меня есть Vec, который «владеет» Person с, но я также хотел бы сопоставить людей с некоторыми другими данными, не касаясь Vec владения или дублирования Person с в памяти. Мол, есть collections::HashMap<&Person, SomeOtherData>. Если бы HashMap и Vec имели одинаковое время жизни, Руст не знал бы, когда освободить Person s?

1 Ответ

0 голосов
/ 24 апреля 2018

«Путь ржавчины» - это путь, который не ведет к небезопасной памяти. Ваш код недействителен, как говорит вам компилятор:

error[E0597]: `person` does not live long enough
  --> src/main.rs:13:26
   |
13 |         personrefs.push(&person);
   |                          ^^^^^^ borrowed value does not live long enough
14 |         persons.push(person);
15 |     }
   |     - `person` dropped here while still borrowed
16 |     println!("persons are {:#?}", persons);
17 | }
   | - borrowed value needs to live until here

Вы создаете Person внутри цикла, беря ссылку на него, затем перемещая Person на новый адрес памяти , аннулируя ссылку. Если вы получили доступ к этой ссылке, вы бы прикоснулись к неопределенной памяти, что в лучшем случае привело бы к segfaults или к «странному поведению» / уязвимостям безопасности в худшем случае.

Аналогично, вы не можете добавить человека в Vec и затем взять ссылку на этого человека в цикле, потому что последующая итерация цикла будет мутировать вектор. Когда вы нажимаете на вектор, он может перераспределить память, снова делая ваши ссылки недействительными.

Я бы написал этот код как

fn main() {
    let persons: Vec<_> = (0..3)
        .map(|x| Person {
            name: format!("Alice-{}", x),
        })
        .collect();

    let personrefs: Vec<_> = persons.iter().collect();
    println!("persons are {:#?}", persons);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...