trait MyTrait {}
struct NullableMyTraitObject<'a>(Option<Box<dyn MyTrait + 'a>>);
impl<'a> NullableMyTraitObject<'a> {
// This doesn't compile.
pub fn get_mut(&mut self) > Option<&mut dyn MyTrait> {
self.0.as_mut().map(boxed boxed.as_mut())
}
// But this does.
pub fn get_mut2(&mut self) > Option<&'_ mut dyn MyTrait> {
self.0.as_mut().map(boxed boxed.as_mut() as _)
}
// This compiles too.
pub fn get_mut3(&mut self) > Option<&mut dyn MyTrait> {
self.0.as_mut().map(boxed { boxed.as_mut() })
}
// But this doesn't.
pub fn get_mut4(&mut self) > Option<&mut dyn MyTrait> {
self.0.as_mut().map(boxed (boxed.as_mut()))
}
// Neither does this.
pub fn get_mut5(&mut self) > Option<&mut dyn MyTrait> {
self.0.as_mut().map(boxed if true {
boxed.as_mut()
} else {
boxed.as_mut()
})
}
// Or this.
pub fn get_mut6(&mut self) > Option<&mut dyn MyTrait> {
self.0.as_mut().map(boxed match true {
true => boxed.as_mut(),
false => boxed.as_mut()
})
}
// The workaround applies here.
pub fn get_mut7(&mut self) > Option<&mut dyn MyTrait> {
self.0.as_mut().map(boxed if true {
boxed.as_mut() as _
} else {
boxed.as_mut() as _
})
}
// And here, too.
pub fn get_mut8(&mut self) > Option<&mut dyn MyTrait> {
self.0.as_mut().map(boxed match true {
true => boxed.as_mut() as _,
false => boxed.as_mut() as _
})
}
}
The compiler complained:
error: lifetime may not live long enough
> src/lib.rs:8:37

5  impl<'a> NullableMyTraitObject<'a> {
  lifetime `'a` defined here
6  // This doesn't compile.
7  pub fn get_mut(&mut self) > Option<&mut dyn MyTrait> {
  let's call the lifetime of this reference `'1`
8  self.0.as_mut().map(boxed boxed.as_mut())
 ^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

help: consider adding 'move' keyword before the nested closure

8  self.0.as_mut().map(move boxed boxed.as_mut())
 ++++
It seems that although we want Option<&'_ mut dyn MyTrait>
(the implicit lifetime comes from &mut self
) as the return type of the closure, the actual inferred type is Option<&'a mut dyn MyTrait>
based on the type of boxed.as_mut()
.
Is it true that the "body" of a closure is not a coercion site unless it is wrapped in {}
as a block? Is this some undocumented detail, since according to Coercion sites in Type coercions  The Rust Reference:
If the expression in one of these coercion sites is a coercionpropagating expression, then the relevant subexpressions in that expression are also coercion sites. Propagation recurses from these new coercion sites. Propagating expressions and their relevant subexpressions are:
 ...
 Parenthesized subexpressions (
(e)
): if the expression has typeU
, then the subexpression is a coercion site toU
. Blocks: if a block has type
U
, then the last expression in the block (if it is not semicolonterminated) is a coercion site toU
. This includes blocks which are part of control flow statements, such asif
/else
, if the block has a known type.
but surrounding the closure "body" with ()
doesn't work as with {}
does.
I think the difference in behavior is quite confusing. Also, the suggestion to add move
keyword is misleading to beginners in this case, and it's quite obvious because the variable involved in the lifetime issue isn't a captured variable.