The first question is the same as being asked e.g. in this thread opened 1 day ago. Any
requires 'static
because Any
allows conversions based on the obtained TypeId
’s, and lifetime information (is “erased” at compiletime and thus) not part of the TypeId
s, so a carelessly designed Any
API without the 'static
requirements might, unsoundly, allow users to convert e.g. StructWithRefs<'a>
into StructWithRefs<'b>
of some different (longer) lifetime.
The second question is answered by looking at how method call resolution works. The “algorithm” described in the linked reference page shows that in ex2
, the first receiver type being considered is the type of s
itself, i.e. &'a StructWithoutRefs
, and that directly matches the &self
receiver type of the type_id
method for the StructWithoutRefs: Any
implementation.
Now in contrast whilst one might expect s.type_id()
in ex3
to be able to (implicitly) convert the &'a mut StructWithoutRefs
to &StructWithoutRefs
, too, in order to match the &self
type, the actual order of types being considered is
&'a mut StructWithoutRefs
& &'a mut StructWithoutRefs
&mut &'a mut StructWithoutRefs
StructWithoutRefs
&StructWithoutRefs
&mut StructWithoutRefs
You’ll see that &'a StructWithoutRefs
does appear, but only fairly late. This is commonly not a problem, so you can for many other traits or inherent methods call a &self
method directly on a &mut Self
reference without any problems. But in this case, the & &'a mut StructWithoutRefs
that comes earlier prevents that, and the compiler decides to go with this receiver type as it matches &self
for the instance &'a mut StructWithoutRefs: Any
. Yes, even a type like &'a mut StructWithoutRefs
implements Any
, just with a where
clause that (effectively) restricts the lifetime to 'a: 'static
. The compiler doesn’t (and frankly cannot) use such a lifetime bound being failed to be met in order to reject this “candidate” in method resolution, it merely says: yep, the type & &'a mut StructWithoutRefs
matches the &self
type for the generic impl<T: 'static> Any for T
implementation, and after this “successful” method resulution, the method call gives rise to the 'a: 'static
bound. Subsequently / down the line the borrow checker will of course catch this bound as problematic in this function and reports the “borrowed data escapes outside of function
– argument requires that `'a` must outlive `'static`
” error. Well, unless you add the 'a: 'static
bound of course, which makes for a weird function signature (with a generic lifetime being effectively restricted to be equal to 'static
), but successfully compiling nonetheless.
With the above observation of how method resolution is relevant in mind, you can actually “fix” ex3
(so that it gets the type id of the StructWithoutRefs
type successfully) by manually creating the &StructWithoutRefs
as in (&*s).type_id()
, or even just by inserting a dereference step and letting the compiler doing the auto-ref (going from *s
to &*s
, i.e. from StructWithoutRefs
to &StructWithoutRefs
) by writing (*s).type_id()
; crucially, this makes sure that the & &'a mut StructWithoutRefs
candidate type never comes up in method resolution, and the first matching type is &StructWithoutRefs
.