Типы черт инвариантны относительно своих общих параметров.
Рассмотрим этот пример:
struct Test<'a, F: Fn(&'a i32)> {
i: &'a i32,
f: F,
}
fn main() {
let i = 1i32;
let t = Test { i: &i, f: |&_| {} };
{
let j = 2i32;
(t.f)(&j);
}
println!("{:?}", t.i);
}
Это даст ошибку:
error[E0597]: `j` does not live long enough
--> src/main.rs:12:15
|
12 | (t.f)(&j);
| ^^ borrowed value does not live long enough
13 | }
| - `j` dropped here while still borrowed
14 |
15 | println!("{:?}", t.i);
| --- borrow later used here
Как видите, тип Test<'a ...
не унифицирован для более короткоговремя жизни с j
, потому что Test
содержит атрибут impal типа N
(статическая отправка).В результате оно будет инвариантно относительно 'a
, следовательно, 'a
не может быть сокращено.Но j
не подходит для 'a
, отсюда и ошибка.
Переходя к вашему вопросу, давайте взглянем на минимальную версию вашего кода:
struct Wrapper<'r, R, N>
where
N: Fn(&'r R),
{
r: &'r mut R,
n: N,
}
impl<'r, R, N> Wrapper<'r, R, N>
where
N: Fn(&'r R),
{
fn myderef(&self) {
(self.n)(self.r)
}
}
Это будетвыдайте ту же ошибку:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/lib.rs:14:18
|
14 | (self.n)(self.r)
| ^^^^^^
|
note: ...the reference is valid for the lifetime 'r as defined on the impl at 9:6...
--> src/lib.rs:9:6
|
9 | impl<'r, R, N> Wrapper<'r, R, N>
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 13:5
--> src/lib.rs:13:5
|
13 | / fn myderef(&self) {
14 | | (self.n)(self.r)
15 | | }
| |_____^
Что именно здесь происходит?&self
с временами жизни будет типа &'shorter_lifetime Wrapper<'r, R, N>
, а не &'shorter_lifetime Wrapper<'shorter_lifetime, R, N>
.'r
не будет сокращено до 'shorter_lifetime
, так как Wrapper
будет инвариантным относительно своего общего параметра времени жизни 'r
из-за N
.
Теперь, когда мы знаем, что именно является типом аргумента &self
есть, давайте посмотрим, что происходит внутри тела myderef()
.Тип черты N
(статическая отправка) вызывается с self.r
.Но self.r
является изменяемой ссылкой, которая переопределяется при передаче в (self.r)()
.Так что теперь у вас есть изменяемая ссылка, которая находится за другой ссылкой (self
является ссылкой), которая должна жить в 'r
(N
нужно, чтобы ее входной аргумент имел время жизни 'r
согласно определению),в результате &self
тоже должен жить для 'r
.Но время жизни &self
составляет 'shorter_lifetime
, отсюда и ошибка.
Другими словами, если у вас есть &'a & 'b mut T
(без отношения подтипов между 'a
и 'b
) в качестве входного аргумента функции, и компилятор позволяет вам перезагружать внутреннюю ссылку и возвращатьэто, то есть нарушение правил заимствования, так как &mut T
уже за ссылкой.Внешняя ссылка «владеет» внутренней ссылкой, главным образом потому, что внутренняя ссылка является изменяемой, и функция нуждается в гарантии того, что внешняя ссылка будет оставаться, по крайней мере, до тех пор, пока внутренняя (изменяемая) ссылка перезагружается, в противном случае после вызова функции тамбудет более одного владельца изменяемой ссылки.
Например, следующий код не будет компилироваться:
fn test<'a, 'b> (i:&'a &'b mut i32) -> &'b i32 {
&**i
}
Но этот будет:
fn test<'a:'b, 'b> (i:&'a &'b mut i32) -> &'b i32 {
&**i
}
поскольку есть гарантия, что 'a
будет жить как минимум столько же, сколько и 'b
.
Если внутренняя ссылка неизменна, то первая также скомпилируется, поскольку вы можете иметь несколько неизменных ссылок.Не существует понятия внешней ссылки, «владеющей» внутренней ссылкой.
Чтобы компилировать минимальную версию, мы должны сообщить компилятору, что &self
также существует для 'r
.Либо это, либо удалите жесткое ограничение 'r
на входной аргумент N
(время жизни).
В вашем примере deref()
не позволит вам указать время жизни для &self
, согласно определению Deref
.Если вы удалите жесткое ограничение 'r
для входного аргумента N
, будет скомпилировано