I want to write a generic function that takes any immutably borrowed iterable container such as an array, Vec , BTreeSet , etc. Since this function is part of a trait that I am implementing, I am not able to change the signature of it, so it's not possible to directly take an iterator as parameter and I also can't introduce any lifetime parameters to the function signature.

Context

I tried to implement the observer pattern in Rust. The observable and the observer look as follows:

struct Observable<T> { value: T, } impl<T> Observable<T> { pub fn get(&self) -> &T { &self.value } } trait Observer<T> { fn update(&self, &Observable<T>); }

(Some functions that were irrelevant to my problem are omitted)

It is now my objective to write an observer that can be used with arbitrary iterable containers which hold items that can be assigned a value. It is supposed to keep track of the sum of values of the items in the container and therefore holds the current sum and a function that calculates the value of any item. It should implement the Observer trait so the sum can be updated each time the container changes.

use std::cell::RefCell; struct SumObserver<T> { current_sum: RefCell<i64>, get_value: Fn(&T) -> i64, }

Approaches so far

I have unsuccessfully tried to get the update function to compile for quite some time. The following is one of the versions of the function that I tried:

impl<'a, T, L> Observer<L> for SumObserver<T> where &'a L: IntoIterator<Item = &'a T>, { fn update(&self, observable: &Observable<L>) { let mut sum: i64 = 0; for item in observable.get() { sum += (self.get_value)(item); } *self.current_sum.borrow_mut() = sum; } }

However, the compiler complains that both parameter types T and L might not live long enough:

error[E0309]: the parameter type `T` may not live long enough --> src/lib.rs:22:1 | 22 | impl<'a, T, L> Observer<L> for SumObserver<T> | ^ - help: consider adding an explicit lifetime bound `T: 'a`... | _| | | 23 | | where 24 | | &'a L: IntoIterator<Item = &'a T>, 25 | | { ... | 32 | | } 33 | | } | |_^ | note: ...so that the reference type `&'a T` does not outlive the data it points at --> src/lib.rs:22:1 | 22 | / impl<'a, T, L> Observer<L> for SumObserver<T> 23 | | where 24 | | &'a L: IntoIterator<Item = &'a T>, 25 | | { ... | 32 | | } 33 | | } | |_^

The error message even stays the same if the whole function body is commented out. If I also remove the where -clause, the compilation works.

If I follow the compiler's suggestion to add explicit lifetime bounds to the parameter types:

impl<'a, T: 'a, L: 'a> Observer<L> for SumObserver<T>

The compiler gives the following error:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements --> src/lib.rs:28:32 | 28 | for item in observable.get() { | ^^^ | note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 26:5... --> src/lib.rs:26:5 | 26 | / fn update(&self, observable: &Observable<L>) { 27 | | let mut sum: i64 = 0; 28 | | for item in observable.get() { 29 | | sum += (self.get_value)(item); 30 | | } 31 | | *self.current_sum.borrow_mut() = sum; 32 | | } | |_____^ note: ...so that reference does not outlive borrowed content --> src/lib.rs:28:21 | 28 | for item in observable.get() { | ^^^^^^^^^^ note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 22:6... --> src/lib.rs:22:6 | 22 | impl<'a, T: 'a, L: 'a> Observer<L> for SumObserver<T> | ^^ = note: ...so that the types are compatible: expected std::iter::IntoIterator found std::iter::IntoIterator