Reputation: 1724
I have this question long ago since from day 1 I started to learn rust. I learned that the implementation for std::fmt::Debug
has a function signature
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result
.
At first I just copy this signature and treat it as a standard boilerplate code. However, as I learned more I realized that <'_>
means lifetime elision. I did some research and according to issue #49469 <'_>
can let the return value infer its lifetime according to parameters (which is really cool). But I also see people use <'_>
extensively with fmt::Formatter
, such as the standard library document and mio, which in these cases <'_>
should not change the default lifetime inference behavior. In addition, I did a quick test with the following code
use std::fmt;
struct Test();
impl fmt::Debug for Test {
fn fmt(&self,fmt:&mut fmt::Formatter) -> fmt::Result {
write!(fmt,"test")?;
Ok(())
}
}
fn main() {
let t = Test();
println!("{:?}",t);
}
and it compiles and runs. So does <'_>
here have some special usages with some edge cases I don't know?
Thanks in advance.
Upvotes: 4
Views: 381
Reputation: 60427
From Rust RFC 2115: Argument Lifetimes:
You can write
'_
to explicitly elide a lifetime, and it is deprecated to entirely leave off lifetime arguments for non-&
types.
And from the included motivation:
[A] point of confusion for newcomers and old hands alike is the fact that you can leave off lifetime parameters for types:
struct Iter<'a> { ... } impl SomeType { // Iter here implicitly takes the lifetime from &self fn iter(&self) -> Iter { ... }
As detailed in the ergonomics initiative blog post, this bit of lifetime elision is considered a mistake: it makes it difficult to see at a glance that borrowing is occurring, especially if you're unfamiliar with the types involved. (The
&
types, by contrast, are universally known to involve borrowing.)
In summary, you should use fmt::Formatter<'_>
.
Upvotes: 5