hfhc2
hfhc2

Reputation: 4421

Why doesn't lifetime elision work for traits

I would like to create my own trait, which should yield a i32 based onindexing with a f32. I tried the following, which does seem to work:

use std::ops::Index;
// trait by value
pub trait MyTrait:
    Index<f32, Output=i32> {
}

While passing an f32 by value may be a good idea, for more complicated types I would rather pass a reference to the value instead, so I tried the following:

// trait by reference, not compiling
pub trait MyTrait:
    Index<&f32, Output=i32> {
}

Including this definition gives me an error[E0106]: missing lifetime specifier. I got this variant working:

// trait by reference, compiling
pub trait MyTrait<'a>:
    Index<&'a f32, Output=i32> {
}

Problem is: While this approach works, it means any type implementing MyTrait needs an explicit lifetime argument.

However, this seems rather unnecessary: If I implement the Index trait for my own struct I don't need any lifetimes:

struct Test {
  value: i32
}

impl Index<&f32> for Test {
  type Output = i32;

  fn index(&self, _key: &f32) -> &Self::Output {
    &self.value
  }
}

Question 1: Why do I need the additional lifetime in the definition of the trait, why can't it be elided?

Question 2: Can I define the trait in such a way as to avoid having to introduce the lifetime?

Upvotes: 0

Views: 291

Answers (2)

Sebastian Redl
Sebastian Redl

Reputation: 72063

As far as I can tell (and I'm not 100% sure, the docs are rather silent on this), this:

impl Index<&f32> for Test { /* ... */ }

is shorthand for this:

impl <'a> Index<&'a f32> for Test { /* ... */ }

In other words, you implement the trait for any lifetime.

Analogously, you can require that the trait is implemented for any lifetime in your bound:

pub trait MyTrait:
    for<'a> Index<&'a f32, Output = i32> {
  // ...
}

Upvotes: 2

edwardw
edwardw

Reputation: 14012

Why do I need the additional lifetime in the definition of the trait, why can't it be elided?

Lifetime elision is only applied to function signature. So no it won't work for your trait definition.

Can I define the trait in such a way as to avoid having to introduce the lifetime?

Certainly, you can use generic parameter just as what std::ops::Index does:

use std::ops::Index;
pub trait MyTrait<T>: Index<T, Output = i32> {}

struct Test {
    value: i32,
}

impl Index<&f32> for Test {
    type Output = i32;

    fn index(&self, _key: &f32) -> &Self::Output {
        &self.value
    }
}

impl MyTrait<&f32> for Test {}

Upvotes: 2

Related Questions