Почему несколько изменяемых ссылок делают невозможным присвоение члена структуры самой себе? [дубликат]
Я не могу брать взаймы там, где думал, что могу. Я свел проблему к этому случаю:
struct A<'a> {
borrow: &'a mut u8,
}
fn does_nothing<'b, 'c>(a: &'b mut A<'c>) {
a.borrow = a.borrow;
}
error[E0623]: lifetime mismatch
--> src/lib.rs:6:16
|
5 | fn does_nothing<'b, 'c>(a: &'b mut A<'c>) {
| -------------
| |
| these two types are declared with different lifetimes...
6 | a.borrow = a.borrow;
| ^^^^^^^^ ...but data from `a` flows into `a` here
Кажется , что a.borrow
есть пересечение 'b
и 'c
поэтому не может быть гарантирована до сих пор срок службы 'c
.
У меня нет реальной проблемы с этим, и я могу обойти это, сделав обе жизни одинаковыми, но почему это не требует проверки?
Кажется, что структуры не важны для демонстрации этой проблемы, и двойные заимствования легко это показывают.
У меня есть три функции, которые очень похожи, но мне было бы трудно понять, какая из них компилируется и какую ошибку выдаст некомпилируемые.
Простая универсальная функция:
fn only_borrow<T>(a: &mut T) {
*a = *a;
}
приводит к ошибке:
error[E0507]: cannot move out of `*a` which is behind a mutable reference
--> src/lib.rs:2:10
|
2 | *a = *a;
| ^^ move occurs because `*a` has type `T`, which does not implement the `Copy` trait
Включение дополнительного уровня косвенного обращения изменяет ошибку
fn only_borrow_double<T>(a: &mut &mut T) {
*a = *a;
}
error[E0623]: lifetime mismatch
--> src/lib.rs:2:10
|
1 | fn only_borrow_double<T>(a: &mut &mut T) {
| -----------
| |
| these two types are declared with different lifetimes...
2 | *a = *a;
| ^^ ...but data from `a` flows into `a` here
Отказ от предполагаемого срока службы может исправить ошибку:
fn working_double<'b, T>(a: &'b mut &'b mut T) {
*a = *a;
}
Ответы
Вам нужно будет взглянуть на свои жизни 'b
и 'c
:
&'b mut ...
означает, что у вас есть ссылка, которая действительна и действительна в течение «времени»'b
.A<'c>
означает, что у вас есть объект, который действителен и действителен'c
.
Чего у вас нет, так это определенной связи между этими двумя жизнями. Единственное, что может сделать компилятор, - это то, что, поскольку оно A<'c>
находится за a &'b
, 'c
должно пережить 'b
, то есть, когда 'b
он действителен, так и есть 'c
. Хотя, главное, не наоборот.
Как вы показываете, компилятор требует 'b
и 'c
должен быть одинакового времени жизни. Почему это?
Давайте посмотрим на наши возможности:
'c
и не'b
имеют отношения: легко видеть, что без какого-либо отношения компилятор не может ничего гарантировать относительно того, что вставлено,A.borrow
и, как таковой, не позволит этого.'c
строго отживает'b
, т. е. кое-где'c
действительно'b
не работает:
a.borrow = a.borrow
становится повторным заимствованиемa
использования время'b
жизни. Этот ответ объясняет, почему это происходит . Однако это означает, чтоa
теперь это зависит от времени'b
жизни, которое не действует в течение некоторого времени,a
является действительным (посколькуa
имеет время жизни'c
). Это дает ошибку.'b
строго переживает'c
: если бы у нас была эта связь, это могло бы сработать. Повторный заимствования будет действителен, поскольку мы получаем "большее" время жизни ('b
), чем мы запрашивали ('c
). Однако мы уже сделали'c: 'b
выводы компилятора за кулисами. Следовательно, добавление этого времени жизни означает, что два времени жизни становятся равными, и мы возвращаемся к тому, с чего начали:
struct A<'a> {
borrow: &'a mut u8,
}
/// We add the relation 'b: 'c
fn does_nothing<'b: 'c, 'c>(a: &'b mut A<'c>) {
a.borrow = a.borrow;
}