I have reduced my actual code to this minimal example:
trait Producer<P> where P: Something {
fn produce(&self) -> Box<P>;
}
struct P1 {}
impl Producer<B1> for P1 {
fn produce(&self) -> Box<B1> {
Box::new(B1 {})
}
}
trait Something {}
trait Borrower<'b> {
type B: std::fmt::Display;
fn borrow(&'b self) -> Self::B;
}
struct B1 {}
impl Something for B1 {}
impl<'b> Borrower<'b> for B1 {
type B = Borrowing1<'b>;
fn borrow(&'b self) -> Self::B {
Borrowing1 { _b: &self }
}
}
struct Borrowing1<'b> {
_b: &'b B1,
}
impl<'b> std::fmt::Display for Borrowing1<'b> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Borrowing1")
}
}
fn perform<'b, P, B>(producer: P) where P: Producer<B>, B: Something + Borrower<'b> + 'static {
for _ in 0..1 {
let b = producer.produce();
let s = b.borrow().to_string();
eprintln!("{}", s);
}
}
fn main() {
let p1 = P1 {};
perform(p1);
}
I have a Producer
type that creates Something
. And that something can implement Borrower<'b>
, which introduces a lifetime. Then, I want to restrict a function perform
to receive producers that produce Something
with the trait Borrower<'b>
. However, since I can't prevent introducing a lifetime in perform
the function thinks that all produced items must live for the entire function execution. Actually, they are static objects that just implement Borrower<'b>
. But I struggle finding the correct bounds.
The error message reflects that:
error[E0597]: `*b` does not live long enough
--> src/main.rs:46:17
|
43 | fn perform<'b, P, B>(producer: P) where P: Producer<B>, B: Something + Borrower<'b> + 'static {
| -- lifetime `'b` defined here
...
46 | let s = b.borrow().to_string();
| ^---------
| |
| borrowed value does not live long enough
| argument requires that `*b` is borrowed for `'b`
47 | eprintln!("{}", s);
48 | }
| - `*b` dropped here while still borrowed
Maybe you can help me with that.
This can be solved using higher-rank trait bounds:
You don't have to pass a lifetime to function here. Instead you need to define a lifetime on the go when borrow()
is called. Following should solve the issue:
fn perform<P, B>(producer: P)
where
P: Producer<B>,
for<'b> B: Something + Borrower<'b> + 'static,
{
for _ in 0..1 {
let b = producer.produce();
let u = b.borrow();
let s = u.to_string();
eprintln!("{}", s);
}
}
Higher-rank trait bounds are explained pretty nicely here:
How does for<> syntax differ from a regular lifetime bound?