In this minimal working example, we have traits Vector and Matrix and a struct MyMatrix modeled as a Vector of (Row)Vectors. The traits have a method "get" that returns a reference to an element. For the matrix we first get a reference to a RowVector and then from it a reference to a matrix element.
trait Vector {
type T;
fn get(&self,i:usize) -> &Self::T;
}
trait Matrix {
type F;
fn get(&self,i:usize,j:usize) -> &Self::F;
}
struct MyMatrix<C>(C);
impl<C:Vector<T=R>,R:Vector<T=F>,F> Matrix for MyMatrix<C> {
type F=F;
fn get(&self,i:usize,j:usize) -> &Self::F {
// ERROR:
// the parameter type `R` may not live long enough
// ...so that the type `R` will meet its required lifetime bound
self.0
.get(i)
.get(j)
}
}
Edit: As Suggested here is the full error message using cargo check
error[E0311]: the parameter type `R` may not live long enough
--> playground/src/main.rs:20:9
|
16 | fn get(&self,i:usize,j:usize) -> &Self::F {
| ----- the parameter type `R` must be valid for the anonymous lifetime defined here...
...
20 | / self.0
21 | | .get(i)
| |___________________^ ...so that the type `R` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
16 | fn get<'a>(&'a self,i:usize,j:usize) -> &'a Self::F where R: 'a {
| ++++ ++ ++ +++++++++++
As you can see we get an error regarding lifetimes. I don't understand the error as to my knowledge the lifetime of the output reference of Vector::get should live as long as the input reference of Vector::get, so R should live, as long as self/matrix.
I could add lifetime annotations to methods/structs/traits to fix this error. However this would force me to add lifetimes annotation across my whole library which would get quite messy. I would much prefer a solution without lifetime annotations. Probably we could also fix the issue by changing the definitions of traits and struct MyMatrix. For example using T and F as a generic type, and not as an associated type. However this would also imply significant changes to my library. I would be interested in a solution which keeps the basic structure and implements my intention that the output of the get functions have the same lifetimes as the input.
This happen because you didn't specify the lifetime of the type, since it is a trait, it can be implement for any type, non-static reference is also a type
consider this:
trait Vector {
type T;
fn get(&self,i:usize) -> &Self::T;
}
trait Matrix {
type F;
fn get(&self,i:usize,j:usize) -> &Self::F;
}
struct MyVector<C>(Vec<C>);
struct MyMatrix<V>(V);
impl<C> Vector for MyVector<C> {
type T = C;
fn get(&self,i:usize) -> &Self::T {
&self.0[i]
}
}
impl<C:Vector<T=R>,R:Vector<T=F>,F> Matrix for MyMatrix<C> {
type F=F;
fn get(&self,i:usize,j:usize) -> &Self::F {
self.0
.get(i)
.get(j)
}
}
fn main () {
let data: Vec<i32> = vec![1,2,3];
let data_ref: Vec<&i32> = data.iter().collect();
let my_vector: MyVector<&i32> = MyVector(data_ref);
let my_matrix: MyMatrix<Vec<MyVector<&i32>>> = MyMatrix(vec![my_vector]);
let my_entry : &i32 = my_matrix.get(0, 1);
drop(my_matrix); // <---
// the source of the reference drop before the reference
// this might happen if C is a non static reference instead of a 'static type
}
To solve that you must guarantee your get
borrow must live long enough,
C
can still be &'a SomeConcreteType
; or'static
referenceI would suggest the second method since I don't think you would want to store reference instead of owned value in the entry of a matrix.
trait Vector : 'static {
type T;
fn get(&self,i:usize) -> &Self::T;
}
related: