Ответ 1
self
имеет тип &mut Foo
в print
, то есть это заимствованная изменяемая ссылка на значение типа Foo
. Типы в Rust переходят в собственность по умолчанию, то есть, принимая что-то по-значение, статически недействительны источник и не позволяют программисту снова использовать его (если он не будет повторно инициализирован). В этом случае unwrap
имеет подпись:
impl Option<T> {
fn unwrap(self) -> T { ...
То есть он принимает значение Option
по значению и, таким образом, пытается поглотить его владение. Следовательно, self.maybe_file.unwrap()
пытается использовать данные в maybe_file
, которые оставят self
, указывая на частично недействительные данные (после этого нельзя использовать поле maybe_file
). Невозможно, чтобы компилятор мог применять это с заимствованными ссылками, которые должны быть действительны всегда, поскольку они могут указывать в любом месте, поэтому незаконно перемещаться.
К счастью, можно избежать этой проблемы: метод as_ref
создает Option<&T>
из &Option<T>
и as_mut
создает Option<&mut T>
из &mut Option<T>
. Получаемый Option
затем больше не находится за ссылкой, поэтому законно использовать его через unwrap
:
let mut file = self.maybe_file.as_mut().unwrap();
Это немного отличается, потому что file
имеет тип &mut File
вместо file
, но, к счастью, &mut File
- это все, что необходимо для остальной части кода.
Другой подход к выполнению этой работы - использование ручной сопоставления шаблонов:
match self.maybe_file {
Some(ref mut file) => println!(...),
None => panic!("error: file was missing")
}
Это делает то же самое, что и .as_mut().unwrap()
, более явно: ref mut
создает ссылку, указывающую непосредственно в память, занятую self.maybe_file
, точно так же, как as_mut
.