2015-04-13 1 views
2

Время жизни ржавчины снова запутывает меня. Я пытаюсь вернуть изменчивую ссылку на объект в коробке, который у меня есть. Вот моя проблема упрощается:as_mut(). Unwrap(): Не удается определить срок службы из-за противоречивых требований.

pub trait Foo { 
    fn foo(&self); 
} 

pub struct Bar { 
    foo: Option<Box<Foo>>, 
} 

impl Bar { 

    pub fn foo(&mut self) -> &mut Box<Foo> { 
     let foo_ref = self.foo.as_mut(); 
     foo_ref.unwrap() 
    } 

    pub fn set_foo(&mut self, value: Box<Foo>) { 
     self.foo = Some(value); 
    } 
} 

я получаю эти ошибки, которые я не очень понимаю:

Compiling testproject v0.0.1 (file:///home/virtlink/projects/orion/testproject) 
src/lib.rs:15:17: 15:25 error: cannot infer an appropriate lifetime due to conflicting requirements 
src/lib.rs:15   foo_ref.unwrap() 
           ^~~~~~~~ 
src/lib.rs:15:9: 15:25 note: first, the lifetime cannot outlive the method call at 15:8... 
src/lib.rs:15   foo_ref.unwrap() 
         ^~~~~~~~~~~~~~~~ 
src/lib.rs:15:9: 15:16 note: ...so that method receiver is valid for the method call 
src/lib.rs:15   foo_ref.unwrap() 
         ^~~~~~~ 
src/lib.rs:13:44: 16:6 note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the block at 13:43... 
src/lib.rs:13  pub fn foo(&mut self) -> &mut Box<Foo> { 
src/lib.rs:14   let foo_ref = self.foo.as_mut(); 
src/lib.rs:15   foo_ref.unwrap() 
src/lib.rs:16  } 
src/lib.rs:15:9: 15:25 note: ...so that expression is assignable (expected `&mut Box<Foo>`, found `&mut Box<Foo>`) 
src/lib.rs:15   foo_ref.unwrap() 
         ^~~~~~~~~~~~~~~~ 
error: aborting due to previous error 
Could not compile `testproject`. 

Я не уверен, как решить эту проблему.

ответ

10

Это случай пожизненного разрешения, а объект по умолчанию ограничивает обратный ход болезненно невидимым способом.

Ошибки абсолютно непрозрачны, так как это плохо. Если заменить .as_mut().unwrap() с сопоставимым match утверждением:

match self.foo { 
    Some(ref mut foo) => foo, 
    None => panic!(), 
} 

вещи становятся немного понятнее:

a.rs:13:34: 13:37 error: mismatched types: 
expected `&mut Box<Foo>`, 
    found `&mut Box<Foo>` 
(lifetime mismatch) [E0308] 
a.rs:13    Some(ref mut foo) => foo, 
             ^~~ 
a.rs:11:44: 16:6 note: the anonymous lifetime #1 defined on the block at 11:43... 
a.rs:11  pub fn foo(&mut self) -> &mut Box<Foo> { 
a.rs:12   match self.foo { 
a.rs:13    Some(ref mut foo) => foo, 
a.rs:14    None => panic!(), 
a.rs:15   } 
a.rs:16  } 
note: ...does not necessarily outlive the static lifetime 
error: aborting due to previous error 

Теперь мы знаем, что происходит несоответствие жизни в где-то в типе &mut Box<Foo>, что анонимное время жизни не обязательно переживает статическое время жизни. В этом типе есть два времени жизни; без какого-либо типа, этот тип - &'a mut Box<Foo + 'b>. Помните, что с объектом-признаком вам все равно нужно указать, как долго может сохраняться объект-объект, следовательно, 'b. В наиболее распространенном случае Box<Trait> эквивалентен Box<Trait + 'static>, что указывает на то, что объект-объект не может содержать никаких нестатических ссылок. (Без этой гарантии безопасность памяти будет нарушена.) В вашем определении структуры время жизни объекта-объекта определяется таким образом как 'static.

Однако указанное время жизни в Box<Trait> не всегда интерпретируется как 'static. Если он содержится в ссылке, то требуемое время жизни сокращается до этого, то есть &'a Box<Trait> интерпретируется как &'a Box<Trait + 'a>.

Таким образом, полная элизия свободной подписи вашего метода на самом деле это:

pub fn foo<'a>(&'a mut self) -> &'a mut Box<Foo + 'a>; 

Теперь, почему это не работает, я не ясно; Я бы подумал, что &'a mut Box<Foo + 'static> (который у вас есть) можно принудить к &'a mut Box<Foo + 'a>, но, по-видимому, это не так; это может быть ошибкой в ​​обработке отклонения (отклонение кода, который должен быть законным), или это может быть не так, я не уверен. Я не понимаю, почему для анонимного жизненного цикла # 1 необходимо пережить статическое время жизни, эта ошибка выглядит так, как будто она управляет жизнями назад.

Во всяком случае, вы действительно хотели вернуть &'a mut Box<Foo + 'static>. Так просто написать 'static в явном виде, и все что надо:

pub fn foo(&mut self) -> &mut Box<Foo + 'static> { 
    self.foo.as_mut().unwrap() 
} 

Другим решением является требование в определении, что тип реализующей Foo всегда должен быть 'static. Тогда Box<Foo + 'a> было бы очевидной ерундой для 'a не обязательно столь же хорошо, как 'static, и это становится разумным и знает, что это должно быть 'static. (Любое ограничение продолжительности жизни для этого признака переопределяет границы объекта по умолчанию.)

Подробнее о границах объектов по умолчанию можно узнать в RFC 599.

+0

Это замечательно, спасибо! Я не знал о жизненной жизни и пробовал 'pub fn foo <'a> (& 'a mut self) -> &' a box Box ' безрезультатно. Как я могу потребовать, чтобы тип, реализующий 'Foo', был' 'static'? Я пробовал 'trait Foo <'static>', но это не работает. – Virtlink

+0

'trait Foo: 'static' –

+0

Возможно, лучшей альтернативой форсированию' 'static' было бы добавить параметр продолжительности жизни в' Bar': 'pub struct Bar <'f> {foo: Option >}'. – rodrigo

Смежные вопросы