0

Here is a code snippet illustrating a lifetimes issue I ran into:

use std::collections::HashSet;

pub trait Store {
    fn put<'a, 'b: 'a>(&mut self, val: &'b str);
}


struct Hstore<'a> {
    hset: HashSet<&'a str>,
}

impl<'a> Store for Hstore<'a> {
    fn put<'b, 'c: 'b>(&mut self, val: &'c str) {
        self.hset.insert(val);
    }
}

My intention is to store referenced values passed by the trait in the struct as long as their lifetimes outlives that of the struct.

A get a compilation error:

error: lifetime may not live long enough
  --> src/lib.rs:14:9
   |
12 | impl<'a> Store for Hstore<'a> {
   |      -- lifetime `'a` defined here
13 |     fn put<'b, 'c: 'b>(&mut self, val: &'c str) {
   |                -- lifetime `'c` defined here
14 |         self.hset.insert(val);
   |         ^^^^^^^^^^^^^^^^^^^^^ argument requires that `'c` must outlive `'a`
   |
   = help: consider adding the following bound: `'c: 'a`

How do I add this 'c: 'a bound? I tried several approaches which did not work.

Also why can't the compile infer the life 'b in the implementation has the same lifetime validity as 'a.

mattgathu
  • 1,129
  • 1
  • 19
  • 28

1 Answers1

1

You can make your trait generic over the lifetime.

pub trait Store<'a> {
    fn put(&mut self, val: &'a str);
}

Then you can easily implement it.

impl<'a> Store<'a> for Hstore<'a> {
    fn put(&mut self, val: &'a str) {
        self.hset.insert(val);
    }
}

This isn't very common, but should work fine. The standard library trait Pattern is very similar, since it also has a method that incorporates a string slice into a type that escapes the function.

An alternative is to make the trait fully generic.

pub trait Store<T> {
    fn put(&mut self, val: T);
}

impl<'a> Store<&'a str> for Hstore<'a> {
    fn put(&mut self, val: &'a str) {
        self.hset.insert(val);
    }
}
drewtato
  • 6,783
  • 1
  • 12
  • 17