Yes, there is a difference.
The method's signature is no different than the one from the docs.
The fact that it looks like this in docs is a fault of rustdoc, and has since been resolved.
If you press [src]
link in the upper right corner of the documentation, you will be redirected to the actual source of Deref
, which looks as follows (I've removed extra attributes and comments):
pub trait Deref {
type Target: ?Sized;
fn deref<'a>(&'a self) -> &'a Self::Target;
}
You can see that deref()
is declared to have a lifetime parameter.
I thought that the difference between specifying the lifetime
parameter on the impl or on the method directly is in the scope of the
parameter only.
And this is wrong. The difference is not in scope only. I don't think I will be able to provide convincing side-by-side examples where a semantic difference is visible, but consider the following reasoning.
First, lifetime parameters are no different from generic type parameters. It is no coincidence that they use similar declaration syntax. Like generic parameters, lifetime parameters participate in the method/function signature, so if you want to implement a trait which has a method with lifetime parameters, your implementation must have the same lifetime parameters as well (modulo possible renaming).
Second, lifetime parameters in impl
signature are used to express different kinds of lifetime relationship than those on functions. For methods, it is always the caller who determines the actual lifetime parameter they want to use. It is, again, similar to how generic methods work - the caller may instantiate its type parameters with any type they need. It is very important, for Deref
in particular - you would want that anything which implements Deref
may be dereferenced with the lifetime of the reference the method is called on, not something else.
With impl
, however, lifetime parameters are chosen not when the method which uses this parameter is called, but when the appropriate impl
is chosen by the compiler. It may do so (and usually does so) based on the type of the value, which precludes the user from specifying arbitrary lifetimes when the method is called. For example:
struct Bytes<'a>(&'a [u8]);
impl<'a> Bytes<'a> {
fn first_two(&self) -> &'a [u8] {
&self.0[..2]
}
}
Here, the first_two()
method returns a slice with a lifetime of the value which is stored inside the Bytes
structure. The caller of the method can't decide which lifetime they want - it is always fixed to the lifetime of the slice inside the structure this method is called on. It is also impossible to bring the lifetime parameter down to the method while keeping the same semantics, I guess you can see why.
In your case the lifetime parameter you specified does not participate either in the signature of the impl
nor in any associated types, so it theoretically could be used as if it was declared on each function separately (because it can be arbitrary when the method is called), but then the reasoning about method signatures (provided above) kicks in.