Ответ 1
Это известная проблема, которая будет решена с помощью нелексических времен жизни, что само по себе основывается на MIR. Если так случится, что вы вставляете в тот же ключ, который ищете, я бы рекомендовал вам использовать API входа.
Вы можете добавить немного неэффективности, чтобы обойти это сейчас.
HashMap
Основная идея состоит в том, чтобы добавить логическое значение, которое сообщает вам, присутствует ли значение или нет. Это логическое значение не зависит от ссылки, поэтому заимствовать не нужно:
use std::collections::BTreeMap;
fn do_stuff(map: &mut BTreeMap<i32, i32>, key: i32) -> Option<&i32> {
if map.contains_key(&key) {
return map.get(&key);
}
map.insert(0, 0);
None
}
fn main() {
let mut map = BTreeMap::new();
do_stuff(&mut map, 42);
println!("{:?}", map)
}
Vec
Подобные случаи могут быть решены с помощью индекса элемента вместо ссылки. Как и в случае выше, это может привести к некоторой неэффективности из-за необходимости еще раз проверять границы срезов.
Вместо
fn find_or_create_five<'a>(container: &'a mut Vec<u8>) -> &'a mut u8 {
match container.iter_mut().find(|e| **e == 5) {
Some(element) => element,
None => {
container.push(5);
container.last_mut().unwrap()
}
}
}
Ты можешь написать:
fn find_or_create_five<'a>(container: &'a mut Vec<u8>) -> &'a mut u8 {
let idx = container.iter().position(|&e| e == 5).unwrap_or_else(|| {
container.push(5);
container.len() - 1
});
&mut container[idx]
}
Non-Lexical Lifetimes
Эти типы примеров являются одним из основных случаев в NLL RFC: Проблемный случай № 3: поток условного управления по функциям.
К сожалению, этот конкретный случай не готов к Rust 1.34. Если вы -Zpolonius
экспериментальную -Zpolonius
ночью, каждый из этих оригинальных примеров будет скомпилирован как есть:
use std::collections::BTreeMap;
fn do_stuff(map: &mut BTreeMap<i32, i32>, key: i32) -> Option<&i32> {
if let Some(key) = map.get(&key) {
return Some(key);
}
map.insert(0, 0);
None
}
fn find_or_create_five(container: &mut Vec<u8>) -> &mut u8 {
match container.iter_mut().find(|e| **e == 5) {
Some(element) => element,
None => {
container.push(5);
container.last_mut().unwrap()
}
}
}
Смотрите также:
-
Как обновить или вставить на Vec?
Это та же самая проблема без возврата ссылки, которая работает с реализацией NLL, доступной в Rust 1.32.
-
Ошибка двойного изменяемого заимствования в цикле происходит даже при включенном NLL
Эта проблема, но в несколько более сложном случае.
-
Когда необходимо обойти проверку Rust заемщика?
Конечный спасательный люк.