Rust: error: lifetime may not live long enough - rust

I am new to rust. Whenever I try call this function, I get an error: lifetime may not live long enough. The error message further says that - argument requires that '1 must outlive '2.
fn get_sizes(dir: &str, listings: &HashMap<&str, Vec<Vec<&str>>>, sizes: &mut HashMap<&str, i32>){
sizes.insert(dir, 0);
}
I want to set the value for key dir to 0 in hashmap sizes.

The problem is exactly what the compiler tells you (even though you did not put the whole message): the lifetime associated with the borrow of dir may be shorter than the one required by sizes. This is because the actual lifetimes are implicit, and all generic.
The solution is very simple: explicitly enforce equality of the lifetimes.
fn get_sizes<'a>(dir: &'a str, listings: &HashMap<&str, Vec<Vec<&str>>>, sizes: &mut HashMap<&'a str, i32>){
sizes.insert(dir, 0);
}
See the playground.

If you read the full error
error: lifetime may not live long enough
--> src/lib.rs:3:5
|
2 | pub fn get_sizes(dir: &str, _listings: &HashMap<&str, Vec<Vec<&str>>>, sizes: &mut HashMap<&str, i32>){
| - let's call the lifetime of this reference `'1` - let's call the lifetime of this reference `'2`
3 | sizes.insert(dir, 0);
| ^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
help: consider introducing a named lifetime parameter
|
2 | pub fn get_sizes<'a>(dir: &'a str, _listings: &HashMap<&str, Vec<Vec<&str>>>, sizes: &mut HashMap<&'a str, i32>){
| ++++ ++ ++
You'll see that you have to enforce dir lives longer than the key in sizes with explicit lifetimes.
Rust even gives you a suggested fix to that problem.
use std::collections::HashMap;
fn get_sizes<'a>(
dir: &'a str,
listings: &HashMap<&str, Vec<Vec<&str>>>,
sizes: &mut HashMap<&'a str, i32>,
) {
sizes.insert(dir, 0);
}

Related

How do I convince the borrow checker that a function call result will not outlive &self

Since posting the original question I have managed to boil the example down to :
trait Bacon {
fn foo(&mut self, x: usize) -> Result<usize, f32>;
}
pub struct Banana<'a> {
phantom: PhantomData<&'a ()>,
}
impl<'a> Banana<'a> {
fn inner_foo(&'a mut self, x: usize) -> Result<usize, Box<dyn Error + 'a>> {
Ok(x)
}
}
impl<'a> Bacon for Banana<'a> {
fn foo(&mut self, x: usize) -> Result<usize, f32> {
self.inner_foo(x).map_err(|_| 0.0)
}
}
The compiler gives me the following error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> /home/thoth/src/rust-esp32-experiments/http-camera/webcam-applib/src/lib.rs:97:18
|
97 | self.inner_foo(x).map_err(|_| 0.0)
| ^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> /home/thoth/src/rust-esp32-experiments/http-camera/webcam-applib/src/lib.rs:96:16
|
96 | fn foo(&mut self, x: usize) -> Result<usize, f32> {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> /home/thoth/src/rust-esp32-experiments/http-camera/webcam-applib/src/lib.rs:97:13
|
97 | self.inner_foo(x).map_err(|_| 0.0)
| ^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> /home/thoth/src/rust-esp32-experiments/http-camera/webcam-applib/src/lib.rs:95:10
|
95 | impl<'a> Bacon for Banana<'a> {
| ^^
note: ...so that the types are compatible
--> /home/thoth/src/rust-esp32-experiments/http-camera/webcam-applib/src/lib.rs:97:18
|
97 | self.inner_foo(x).map_err(|_| 0.0)
| ^^^^^^^^^
= note: expected `&mut Banana<'_>`
found `&mut Banana<'a>`
I think my code is safe, and the Box<dyn Error+'a> will not outlive &self, but there might be some other lifetime issue I have overlooked.
kmdreko mentions that 'a is more constrained than'_, but I'm not sure how to rework inner_foo to capture the lifetime characteristics of the Box contents.
I tried changing the return type of read_inner to Result<usize, Box<dyn Error + 'static>> , but that gave me a lot of errors, and suggested that I add 'static' to elements of the where clause (ES, EI), which would ripple up through the call hierarchy. I was hoping to use the map_err as a firewall to avoid that.
cargo 1.62.1-nightly (a748cf5a3 2022-06-08)
rustc 1.62.1-nightly (e4f2cf605 2022-07-19)
How can I convince the compiler that my code is safe?
I have currently moved past this problem without solving it using the <'b> technique suggested by kmdreko. I had to modify large chunks of the rest of the app to make it work (and patch the crate that specifies the trait), so the original question is still of interest.

Returning a higher-kinded closure that captures a reference

I'm trying to write a method on a struct that returns a closure. This closure should take a &[u8] with an arbitrary lifetime 'inner as an argument and return the same type, &'inner [u8]. To perform its function, the closure also needs a (shared) reference to a member of the struct &self. Here is my code:
#![warn(clippy::pedantic)]
// placeholder for a large type that I can't afford to clone
struct Opaque(usize);
struct MyStruct<'a>(Vec<&'a Opaque>);
impl<'a> MyStruct<'a> {
pub fn get_func_for_index(
&'a self,
n: usize,
) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
// the reference to the struct member, captured by the closure
let opaque: &'a Opaque = *self.0.get(n)?;
Some(move |i: &[u8]| {
// placeholder: do something with the input using the &Opaque
&i[opaque.0..]
})
}
}
fn main() {
let o1 = Opaque(1);
let o5 = Opaque(5);
let o7 = Opaque(7);
let x = MyStruct(vec![&o1, &o5, &o7]);
let drop_five = x.get_func_for_index(1 /*Opaque(5)*/).unwrap();
let data: Vec<u8> = Vec::from(&b"testing"[..]);
assert_eq!(drop_five(&data[..]), b"ng");
}
If I try to compile it with rustc 1.54.0 (a178d0322 2021-07-26), I get the following error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> /tmp/lifetimes.rs:16:14
|
16 | &i[opaque.0..]
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 14:14...
--> /tmp/lifetimes.rs:14:14
|
14 | Some(move |i: &[u8]| {
| ______________^
15 | | // placeholder: do something with the input using the &Opaque
16 | | &i[opaque.0..]
17 | | })
| |_________^
note: ...so that reference does not outlive borrowed content
--> /tmp/lifetimes.rs:16:14
|
16 | &i[opaque.0..]
| ^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 6:6...
--> /tmp/lifetimes.rs:6:6
|
6 | impl<'a> MyStruct<'a> {
| ^^
note: ...so that return value is valid for the call
--> /tmp/lifetimes.rs:10:17
|
10 | ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: higher-ranked subtype error
--> /tmp/lifetimes.rs:7:5
|
7 | / pub fn get_func_for_index(
8 | | &'a self,
9 | | n: usize,
10 | | ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
| |_______________________________________________________________________^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0495`.
It's quite a mouthful and I don't really understand what it's trying to tell me. The first part (first, the lifetime...) makes sense to me, the returned slice must not outlive the closure argument. The second part (but, the lifetime...) however seems weird to me - the + 'a annotation in the method signature refers to the closure itself (because it captures &'a self.foo), not to the value the closure returns.
Is it possible to change the code to model this correctly in rust, or is this construct just not supported at this time?
The problem is here:
Some(move |i: &[u8]| {
Every & has a lifetime on it, explicit or not. What is the lifetime of &[u8]? Clearly it should be "a lifetime chosen by the caller of the closure" (that is, a higher-ranked lifetime). But when the compiler encounters a reference type with a free lifetime parameter, even in the argument list of a closure, it will not assume that the lifetime is higher-ranked. The error message you get about the "anonymous lifetime #1" is the compiler confusedly trying to make a non-higher-ranked lifetime work.
The compiler could, in theory, work "backwards" from the impl Fn in the return type and recognize that the type of the closure needs to have this higher ranked lifetime. It's not quite clever enough to do that in this case, but there is a way to convince it: use a local function with a bounded type parameter to constrain the type of the closure to exactly the bound you want.
pub fn get_func_for_index(
&self, // note 1
n: usize,
) -> Option<impl 'a + for<'inner> Fn(&'inner [u8]) -> &'inner [u8]> { // note 2
// the reference to the struct member, captured by the closure
let opaque: &'a Opaque = *self.0.get(n)?;
// helper function to constrain the closure type
fn check<F: Fn(&[u8]) -> &[u8]>(f: F) -> F { // note 3
f
}
Some(check(move |i| {
// placeholder: do something with the input using the &Opaque
&i[opaque.0..]
}))
}
Playground
Please note the following:
&'a self is too conservative for this function because 'a is the lifetime parameter of the reference self contains, not the lifetime for which self is borrowed. In general, you should almost never write &'a self or &'a mut self where 'a is a named lifetime from an outer scope.
I find the + 'a easy to miss at the end of a long trait, especially a Fn trait with a return type. I recommend fronting the lifetime (putting it first) in cases like this to make clear that it relates more to the impl than to the &'inner [u8]. This is a stylistic choice.
Fn(&[u8]) -> &[u8] is actually exactly the same as for<'inner> Fn(&'inner [u8]) -> &'inner [u8], because the elision rules for Fn traits are the same as for regular functions. Either way is fine; I find the shorter version easier to read.
Similar questions
Expected bound lifetime parameter, found concrete lifetime [E0271]
How to declare a higher-ranked lifetime for a closure argument?
Why does this closure require inlining or `dyn`? What does `dyn` do here?

What is the implicit lifetime for the 1st argument when the 2nd argument is annotated with 'a?

While reading Chapter 12.4 of the Rust Book, I stumbled upon this function:
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
I understand why the code doesn't compile without the explicit lifetime annotation for the contents argument and the return value - the lifetime elision rules do not apply for functions with at least two borrowed arguments.
But I'm curious what's the implicit lifetime annotation for the query argument. I could think of two scenarios:
// Scenario 1
pub fn search<'a>(query: &'a str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
// Scenario 2
pub fn search<'a, 'b>(query: &'b str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
Both scenarios compile, so query gets either lifetime 'a or 'b. Which one is correct?
From the rustonomicon, under lifetime elision:
Each elided lifetime in input position becomes a distinct lifetime parameter.
You can try assigning the function to a wrong type. Compiler will tell you the correct type of the function:
let x: () = search;
Playground
Result:
error[E0308]: mismatched types
--> src/main.rs:6:17
|
6 | let x: () = search;
| -- ^^^^^^ expected `()`, found fn item
| |
| expected due to this
|
= note: expected unit type `()`
found fn item `for<'r, 'a> fn(&'r str, &'a str) -> Vec<&'a str> {search}`
So, type of your function is:
for<'r, 'a> fn(&'r str, &'a str) -> Vec<&'a str> {search}
Also, if query also had lifetime 'a, you should be able to do this:
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
vec![query]
}
But this fails to compile because query's lifetime is not 'a.
Playground
One way to think of it is that we're not 'giving' a lifetime with lifetime annotations, but describing how the lifetime of your return value relates to the lifetimes of your inputs.
Lifetimes already exist, but annotations let us set relations between them. As you never relate the lifetime of query to anything else in situation 2, we shouldn't really need to name it. Intuitively this makes sense as the most common case and the one that the compiler should (does) infer if you make no annotation on query.

What exactly is the logic of a borrow checker in the case of nested references with the same lifetime? [duplicate]

Trying to compile this program I get stuck on the borrow checker:
use std::collections::BTreeMap;
type Object<'a> = BTreeMap<&'a str, i32>;
struct Root<'a>(Object<'a>);
struct Sub<'a>(&'a mut Object<'a>, &'a str);
impl<'a> Root<'a> {
fn borrow_mut(&'a mut self, data: &'a str) -> Sub<'a> {
Sub(&mut self.0, data)
}
fn borrow(&self) {
println!("{:?}", self.0);
}
}
fn main() {
let mut me = Root(Object::new());
{
me.borrow_mut("data!");
}
me.borrow();
}
(Playground)
I get:
error[E0502]: cannot borrow `me` as immutable because it is also borrowed as mutable
--> src/main.rs:24:5
|
22 | me.borrow_mut("data!");
| -- mutable borrow occurs here
23 | }
24 | me.borrow();
| ^^ immutable borrow occurs here
25 | }
| - mutable borrow ends here
It looks like the mutable borrow should end before me.borrow() but the borrow checker insists that it ends when main ends.
To quickly explain what I'm trying to accomplish:
Make a parent struct to hold data
Make a sub category of data and store it in the parent
Use this builder style pattern to make MongoDB Queries
You are running afoul of a lifetime issue.
There are multiple different lifetimes in your program:
type Object<'a> = BTreeMap<&'a str, i32>; => this is one
&'a mut Object<'a> => there are up to TWO here
struct Sub<'a>(&'a mut Object<'a>, &'a str); => there are up to THREE here
There is, apparently, no reason for the reference to Object<'a> to have the same lifetime than the &str inside the BTreeMap. However, you told the compiler that you wanted both lifetimes to be the same!
When you write:
struct Sub<'a>(&'a mut Object<'a>, &'a str);
you are telling the compiler that:
the lifetime of the &str inside BTreeMap
the lifetime of the reference to Object<'_>
the lifetime of the &str accompanying the Object<'_>
are all one and the same.
You have over-constrained the requirements; and as a result no solution can satisfy them.
Adding one more degree of freedom is sufficient! We'll just make the lifetime of the reference to Object<'_> different from the lifetime of those &str floating around:
struct Sub<'a, 'b: 'a>(&'a mut Object<'b>, &'b str);
impl<'b> Root<'b> {
fn borrow_mut<'a>(&'a mut self, data: &'b str) -> Sub<'a, 'b> {
Sub(&mut self.0, data)
}
fn borrow(&self) {
println!("{:?}", self.0);
}
}
Note the subtle 'b: 'a:
Object<'b> contains a reference to something whose lifetime is 'b
the lifetime of the reference to Object<'b> (denoted 'a) must be SHORTER than 'b (otherwise you have a reference to something dead?)
Thus, we say that 'b outlives 'a with 'b: 'a.
And that's it. Simply loosening the requirements allow the compiler to allow your code to compile.
Note that in general, if you find yourself writing something like &'a &'a str you are doing it wrong. If you think about it, you will realize that in order to create a reference to something, it must first be. And therefore a reference to an object necessarily has a shorter lifetime than the object itself (ever so slightly).

Mutable borrow seems to outlive its scope

Trying to compile this program I get stuck on the borrow checker:
use std::collections::BTreeMap;
type Object<'a> = BTreeMap<&'a str, i32>;
struct Root<'a>(Object<'a>);
struct Sub<'a>(&'a mut Object<'a>, &'a str);
impl<'a> Root<'a> {
fn borrow_mut(&'a mut self, data: &'a str) -> Sub<'a> {
Sub(&mut self.0, data)
}
fn borrow(&self) {
println!("{:?}", self.0);
}
}
fn main() {
let mut me = Root(Object::new());
{
me.borrow_mut("data!");
}
me.borrow();
}
(Playground)
I get:
error[E0502]: cannot borrow `me` as immutable because it is also borrowed as mutable
--> src/main.rs:24:5
|
22 | me.borrow_mut("data!");
| -- mutable borrow occurs here
23 | }
24 | me.borrow();
| ^^ immutable borrow occurs here
25 | }
| - mutable borrow ends here
It looks like the mutable borrow should end before me.borrow() but the borrow checker insists that it ends when main ends.
To quickly explain what I'm trying to accomplish:
Make a parent struct to hold data
Make a sub category of data and store it in the parent
Use this builder style pattern to make MongoDB Queries
You are running afoul of a lifetime issue.
There are multiple different lifetimes in your program:
type Object<'a> = BTreeMap<&'a str, i32>; => this is one
&'a mut Object<'a> => there are up to TWO here
struct Sub<'a>(&'a mut Object<'a>, &'a str); => there are up to THREE here
There is, apparently, no reason for the reference to Object<'a> to have the same lifetime than the &str inside the BTreeMap. However, you told the compiler that you wanted both lifetimes to be the same!
When you write:
struct Sub<'a>(&'a mut Object<'a>, &'a str);
you are telling the compiler that:
the lifetime of the &str inside BTreeMap
the lifetime of the reference to Object<'_>
the lifetime of the &str accompanying the Object<'_>
are all one and the same.
You have over-constrained the requirements; and as a result no solution can satisfy them.
Adding one more degree of freedom is sufficient! We'll just make the lifetime of the reference to Object<'_> different from the lifetime of those &str floating around:
struct Sub<'a, 'b: 'a>(&'a mut Object<'b>, &'b str);
impl<'b> Root<'b> {
fn borrow_mut<'a>(&'a mut self, data: &'b str) -> Sub<'a, 'b> {
Sub(&mut self.0, data)
}
fn borrow(&self) {
println!("{:?}", self.0);
}
}
Note the subtle 'b: 'a:
Object<'b> contains a reference to something whose lifetime is 'b
the lifetime of the reference to Object<'b> (denoted 'a) must be SHORTER than 'b (otherwise you have a reference to something dead?)
Thus, we say that 'b outlives 'a with 'b: 'a.
And that's it. Simply loosening the requirements allow the compiler to allow your code to compile.
Note that in general, if you find yourself writing something like &'a &'a str you are doing it wrong. If you think about it, you will realize that in order to create a reference to something, it must first be. And therefore a reference to an object necessarily has a shorter lifetime than the object itself (ever so slightly).

Resources