The Rust compiler gives me a lifetime error with the following code (which is a minimal working example of some real code):
pub trait TElement: Copy {
// Details irrelevant
}
pub trait TSet<'a, I, E>
where
E: 'a + TElement,
I: IntoIterator<Item = &'a E>
{
fn elements(&'a self) -> I;
fn nr_elements(&'a self) -> usize;
}
#[derive(Clone, Copy)]
pub struct Element {
// Details irrelevant
}
impl TElement for Element {}
pub struct VecSet<E>
where E: TElement
{
elements: Vec<E>
}
impl<'a, E> TSet<'a, &'a Vec<E>, E> for VecSet<E>
where E: TElement
{
fn elements(&'a self) -> &'a Vec<E>
{
&self.elements
}
fn nr_elements(&'a self) -> usize {
self.elements.len()
}
}
pub fn split<'a, S, I, E>(s: &'a S) -> Vec<VecSet<E>>
where
E: 'a + TElement,
I: IntoIterator<Item = &'a E>,
S: TSet<'a, I, E>
{
// Dummy: Produce batches of size 1
let mut batches = Vec::<VecSet<E>>::with_capacity(s.nr_elements());
for &element in s.elements() {
batches.push(VecSet { elements: vec![element] } );
}
batches
}
pub trait TCalculator<'a, S, I, E>
where
E: 'a + TElement,
I: IntoIterator<Item = &'a E>,
S: TSet<'a, I, E>
{
fn calc(&self, set: &'a S) -> i32;
}
pub struct Calculator {}
impl<'a, S, I, E> TCalculator<'a, S, I, E> for Calculator
where
E: 'a + TElement,
I: IntoIterator<Item = &'a E>,
S: TSet<'a, I, E>
{
fn calc(&self, set: &'a S) -> i32
{
set.elements().into_iter().count() as i32
}
}
pub fn summarize<'a, S, I, E, C>(set: &'a S, calculator: C) -> i32
where
E: 'a + TElement,
I: IntoIterator<Item = &'a E>,
S: TSet<'a, I, E>,
C: TCalculator<'a, VecSet<E>, &'a Vec<E>, E>
{
let set_of_sets = split(set);
set_of_sets
.iter()
.map(|s| calculator.calc(s))
.sum()
}
fn main() {
let set = VecSet { elements: vec![Element {}, Element {}] };
let sum: i32 = summarize(&set, Calculator {});
println!("Sum = {}", sum); // Supposed to print: Sum = 2
}
The error is on set_of_sets in the function summarize: Borrowed value does not live long enough. The explanation given: The argument in calculator.calc(s) requires that set_of_sets is borrowed for 'a, but set_of_sets is dropped at the end of the function while still borrowed.
I kind of understand why the error comes up, but I do not know how to solve it.
Full compilation error:
error[E0597]: `set_of_sets` does not live long enough
--> src/main.rs:89:5
|
81 | pub fn summarize<'a, S, I, E, C>(set: &'a S, calculator: C) -> i32
| -- lifetime `'a` defined here
...
88 | let set_of_sets = split(set);
| ----------- binding `set_of_sets` declared here
89 | set_of_sets
| ^^^^^^^^^^^ borrowed value does not live long enough
90 | .iter()
91 | .map(|s| calculator.calc(s))
| ------------------ argument requires that `set_of_sets` is borrowed for `'a`
92 | .sum()
93 | }
| - `set_of_sets` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
If you change trait TSet<'a, I, E> to merely trait TSet<E> and make I an impl Trait return type, things simplify drastically and you solve all your lifetime issues.
pub trait TElement: Copy {
// Details irrelevant
}
pub trait TSet<E>
where
E: TElement,
{
fn elements<'a>(&'a self) -> impl IntoIterator<Item = &'a E>
where
E: 'a;
fn nr_elements(&self) -> usize;
}
#[derive(Clone, Copy)]
pub struct Element {
// Details irrelevant
}
impl TElement for Element {}
pub struct VecSet<E>
where
E: TElement,
{
elements: Vec<E>,
}
impl<E> TSet<E> for VecSet<E>
where
E: TElement,
{
fn elements<'a>(&'a self) -> impl IntoIterator<Item = &'a E>
where
E: 'a,
{
&self.elements
}
fn nr_elements(&self) -> usize {
self.elements.len()
}
}
pub fn split<S, E>(s: &S) -> Vec<VecSet<E>>
where
E: TElement,
S: TSet<E>,
{
// Dummy: Produce batches of size 1
let mut batches = Vec::<VecSet<E>>::with_capacity(s.nr_elements());
for &element in s.elements() {
batches.push(VecSet {
elements: vec![element],
});
}
batches
}
pub trait TCalculator<S, E>
where
E: TElement,
S: TSet<E>,
{
fn calc(&self, set: &S) -> i32;
}
pub struct Calculator {}
impl<S, E> TCalculator<S, E> for Calculator
where
E: TElement,
S: TSet<E>,
{
fn calc(&self, set: &S) -> i32 {
set.elements().into_iter().count() as i32
}
}
pub fn summarize<S, E, C>(set: &S, calculator: C) -> i32
where
E: TElement,
S: TSet<E>,
C: TCalculator<VecSet<E>, E>,
{
let set_of_sets = split(set);
set_of_sets.iter().map(|s| calculator.calc(s)).sum()
}
fn main() {
let set = VecSet {
elements: vec![Element {}, Element {}],
};
let sum: i32 = summarize(&set, Calculator {});
println!("Sum = {}", sum); // Supposed to print: Sum = 2
}