По какой причине выдается вышеуказанная ошибка? Считает ли это
владение изменяемой ссылкой, и он видит что-то (из Foo
)
вынимается (с независимым временем жизни), который не
возможно, отсюда и ошибка?
Изменяемый заем действительно не может быть перемещен из Foo, поскольку изменяемые заимствования не Copy
. Неявно заимствовано:
fn func <'a, 'b> (x:&'a Foo<'b>) -> &'b i32 {
&*x.i
}
Однако это не является источником проблемы. Во-первых, вот краткое изложение четырех версий func
(struct Foo
не имеет отношения к моему объяснению):
версия 1 (компилируется):
fn func<'a, 'b>(x: &'a &'b i32) -> &'b i32 {
x
}
версия 2 (не компилируется):
fn func<'a, 'b>(x: &'a &'b mut i32) -> &'b i32 {
x
}
версия 3 (не компилируется):
fn func<'a, 'b: 'a>(x: &'a &'b mut i32) -> &'b i32 {
x
}
версия 4 (компилируется):
fn func<'a: 'b, 'b>(x: &'a &'b mut i32) -> &'b i32 {
x
}
Версии 2 и 3 терпят неудачу, потому что они нарушают правило отсутствия псевдонимов, которое запрещает иметь изменяемую ссылку и неизменную ссылку на ресурс одновременно. В обеих версиях 'b
может строго пережить 'a
. Следовательно, &'b mut i32
и &'b i32
могут сосуществовать. Версия 1 компилируется, потому что правила псевдонимов допускают несколько неизменных ссылок на ресурс одновременно. Следовательно, &'b i32
может юридически сосуществовать с другим &'b i32
.
На первый взгляд, похоже, что версия 4 должна потерпеть неудачу, поскольку снова возникают изменяемые заимствования и неизменные заимствования того же времени жизни. Разница между версиями 2 и 3 заключается в том, что на этот раз 'a
живет по крайней мере столько же, сколько 'b
из-за требования 'a: 'b
, что означает, что 'b
может не строго пережить 'a
, Пока время жизни 'a
длится, ссылочная i32
не может быть заимствована повторно во второй раз (изменяемые ссылки не Copy
) - i32
уже зарезервировано заимствована для вызова func
.
Вот пример, демонстрирующий, как версии 2 и 3 могут привести к неопределенному поведению:
fn func<'a, 'b: 'a>(x: &'a &'b mut String) -> &'b str {
unsafe { std::mem::transmute(&**x as &str) } // force compilation
}
fn main() {
let mut s = String::from("s");
let mutref_s = &mut s;
let ref_s = {
let ref_mutref_s = &mutref_s;
func(ref_mutref_s)
};
// use the mutable reference to invalidate the string slice
mutref_s.clear();
mutref_s.shrink_to_fit();
// use the invalidated string slice
println!("{:?}", ref_s);
}
Замена версии 3 на версию 4 показывает, как в этом случае все еще активный внешний неизменяемый заем предотвращает второе изменяемое заимствование. Срок жизни 'a
для внешнего неизменного заимствования вынуждается новым требованием 'a: 'b
быть увеличенным до времени жизни 'b
:
error[E0502]: cannot borrow `*mutref_s` as mutable because `mutref_s` is also borrowed as immutable
--> src/main.rs:20:5
|
17 | let ref_mutref_s = &mutref_s;
| -------- immutable borrow occurs here
...
20 | mutref_s.clear();
| ^^^^^^^^ mutable borrow occurs here
...
23 | }
| - immutable borrow ends here