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
.
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);
}
}