Maybe I forgot something. I have been "away from Rust" for a few weeks.
I browsed the source code of the Error trait and saw this:
impl Error + 'static {
/// Returns true if the boxed type is the same as `T`
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
// Get TypeId of the type this function is instantiated with
let t = TypeId::of::<T>();
// Get TypeId of the type in the trait object
let boxed = self.type_id();
// Compare both TypeIds on equality
t == boxed
}
...
I am particularly interested in the impl Error + 'static here. Error is trait. How can I impl a trait?
1 Like
I was confused over it as well
Confusion about impls without for
In Rust, pure T denotes a trait object type.
1 Like
Thank you.
So that implements methods for the trait object. In the case Error + 'static that means methods on Box<Error>. Am I right?
Also, isn't the 'static bound inferred if I don't specify it for a trait object? So impl Error + 'static is actually the same as impl Error?
Yep. Or on &Error.
Also, isn’t the 'static bound inferred if I don’t specify it for a trait object? So impl Error + 'static is actually the same as impl Error?
Not sure about this one. I think Box<Error> is a special case of lifetime elision.
I think Box<Trait> is implicitly Box<Trait + 'static>. I'd imagine Box<Error> is no different.
My guess about that is that impl Error + 'static is a leftover from before default trait bounds were defined, but I'm not certain either.
I don't want to transform this into a grokking-lifetime-issue but I created an example and I don't really understand the result:
trait Foo {
}
impl Foo {
fn lol(&self) { println!("Hello, world"); }
}
impl Foo for Bar {}
#[derive(Debug)]
struct Bar {
v: i32,
}
fn main() {
let b = Bar { v: 100 };
let o: &Foo = &b;
o.lol();
}
fn does_not_work(o: &Foo) {
o.lol();
}
With the function does_not_work(o: &Foo) I get my expected result. The method lol() requires &'static Foo. It does not work for an arbitrary lifetime, because the impl Foo mandates 'static. But why does the &Foo in the main function work? Is o an &'static Foo there? Is this some kind of static promotion behind the scenes?
You absolutely should - you and others can benefit.
The reason is because Trait + 'static means the type implementing the trait must have no references or only 'static references - it doesn't mean the lifetime of a reference to the Trait object itself has to be 'static.
Your Bar struct has no references, so it satisfies Trait + 'static when turned into a Foo trait object. That's why main works.
Your does_not_work function says it takes &Foo, which is essentially &'elided_lifetime(Foo + 'elided_lifetime), but it needs 'static to call lol. Two ways around this:
- Use
impl<'a> Foo + 'a {...} to allow lol to be called for a trait object with a generic lifetime.
- Change does_not_work param to be
&(Foo + 'static)
2 Likes
Ah, yes. Trait + 'a concerns the actual erased type of the trait object. Damn it. I actually knew that! Thanks for the great explanation though. 