fn main() {
fn foo<T>(x: T, _m: T) -> T {
x
}
let x = 0;
let mut n;
{
let m = 10;
n = foo(&x, &m);
}
println!("{}", n);
}
The above code will prompt after compilation:
error[E0597]: `m` does not live long enough
--> src/main.rs:10:21
|
9 | let m = 10;
| - binding `m` declared here
10 | n = foo(&x, &m);
| ^^ borrowed value does not live long enough
11 | }
| - `m` dropped here while still borrowed
12 | println!("{}", n);
| - borrow later used here
Also, what is the lifetime used for the generic parameter of the foo function after monomorphism in the following code
fn main() {
trait Animal<'c>: Send + Sized {
fn execute<'e, 'q: 'e, E: 'q>(self, _query: E)
where
'c: 'e,
E: Animal<'q>,
{
}
}
impl<'a> Animal<'a> for &'_ i32 {}
fn foo<'e, 'c: 'e, E>(_executor: E)
where
E: 'e + Animal<'c>,
{
}
let x = 0;
foo(&x);
}
My question is how is the lifetime limited during generic monomorphism? Do you have any relevant documents? Thank you for your reply
says that both parameters have to have the same type, and it also returns that same type. The type includes any lifetimes (e.g. the lifetime of a reference). So here:
{
let m = 10;
n = foo(&x, &m);
}
The lifetime of &m can't be larger than the inner block, or it would dangle. The lifetime of &x and that in the value stored in n must be the same, because they're all the same type parameter in the call. Thus n cannot be usable outside the inner block.
(Additionally the function signature is the contract, and the contract allows you to return _m and not x from foo. The body of the function doesn't enter into lifetime checking at the call site, only the signature. The compiler has to assume you might return _m, since that's what the signature means.)
Part 2
The lifetime is any one that meets the constraints imposed by lifetime bounds and how the values are used. In this case you can consider the lifetime to be one that ends immediately after the call to foo as there is nothing causing it to last longer.
fn main() {
fn bar<'b, 'a: 'b>(x: &'a i32, _m: &'b i32) -> &'a i32 {
x
}
let x = 1;
let n;
{
let m = 10;
n = bar(&x, &m);
}
println!("{}", n);
}
The above code compiles normally after adding lifetimes parameters.
I understand the usage of lifetimes, but I do not understand how to add lifetimes constraints to reference parameters during normalization of generic parameters.
You don't need 'a: 'b constraint, and write fn bar<'b, 'a> instead. The reason is you're returning a reference only related to 'a and irrelevant to 'b, so 'a and 'b are not connected.
The basic idea of lifetime annotation is to convey the intent of lifetime connections and contract the caller must adhere.
fn main() {
fn foo<T>(x: T, _m: T) -> T {
x
}
let x = 0;
let mut n;
{
let m = 10;
n = foo(&x, &m);
}
println!("{}", n);
}
In the generic example, it is because during generic monomorphism, two parameters use the same lifetimes parameter, resulting in a failure of lifetimes checking. When a function has two or more generic parameters and the type of the parameter is a reference type, are all parameters using the same lifetimes during generic monomorphism?
Perhaps this signature would help with your problem? Here the reference is not part of the type parameter, so each function parameter can have a different lifetime while still sharing a common referent type.
fn bar<'b, 'a: 'b, T>(x: &'a T, _m: &'b T) -> &'a T {
x
}
fn main() {
fn foo<T>(x: T, _m: T) -> T {
x
}
fn bar(x: &i32, _m: &i32) -> &i32 {
x
}
let (x, y) = (1, 2);
foo(&x, &y);
bar(&x, &y);
}
What is the difference in lifetime between the foo and bar functions in the above code? Why can foo function compilation pass? Thank you for your reply!