Rust - Lifetimes - Understanding Lifetime Error for mutable reference to self - rust

I'm sure this is a duplicate, but I can't find a question which matches my question, exactly since I have a couple extra requirements because I have to adhere to some traits that I can't control.
Here is my code. I apologize for the sort of convoluted example, but this was the most I could minimize it as I am trying to implement a custom serialization format using the serde library.
// Doesn't really matter what this struct contains, it just needs an owning method
struct SideStruct;
impl SideStruct {
fn something_side<A: TraitA>(&self, aval: A) {
println!("something sideways :)");
aval.something_a(42)
}
}
trait TraitA {
fn something_a(&mut self, data: u32); // this would be the meat of my logic
}
// Note that this struct has an explicit lifetime
struct MainStruct<'a> {
refr: &'a mut u32
}
// Note that I implement for a mutable reference to MainStruct
impl<'a> TraitA for &'a mut MainStruct<'a> {
fn something_a(&mut self, data: u32) {
// Completely arbitrary, can safely ignore this function body
*self.refr += data;
println!("We're finally doing something: {}", self.refr);
}
}
// Implementing for MainStruct itself
impl<'a> MainStruct<'a> {
// Note, I can't change the signature for this function because it implements a trait
fn something_indirect(&mut self, ss: &SideStruct) {
// here is where the error occurs!
ss.something_side(self)
}
}
fn main() {
let mut base_val: u32 = 42;
let ss = SideStruct {};
let mut main_val = MainStruct { refr: &mut base_val };
main_val.something_indirect(&ss);
}
This is the error I got:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:27
|
28 | ss.something_side(self)
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/main.rs:27:27
|
27 | fn something_indirect(&mut self, ss: &SideStruct) {
| ^^^^^^^^^
note: ...so that the expression is assignable
--> src/main.rs:28:27
|
28 | ss.something_side(self)
| ^^^^
= note: expected `&mut MainStruct<'a>`
found `&mut MainStruct<'a>`
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/main.rs:26:6
|
26 | impl<'a> MainStruct<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:28:12
|
28 | ss.something_side(self)
| ^^^^^^^^^^^^^^
= note: expected `<&mut MainStruct<'a> as TraitA>`
found `<&mut MainStruct<'_> as TraitA>`
For more information about this error, try `rustc --explain E0495`.
I don't know what the compiler means when it states that note: first, the lifetime cannot outlive the anonymous lifetime defined here.... Does it mean that some constraint forces self to not outlast the method something_indirect? That makes no sense. Also the message so that the expression is assignable confuses me. MainStruct should not be assigned when something_side is called on it right? Since I implemented TraitA for a mutable reference to MainStruct, shouldn't I be able to call something_side with a mutable reference to MainStruct by passing self? Anyways, thanks for the help, and have a great day!

The trouble is that in order to use the method defined, you must borrow the MainStruct as mutable with an anonymous lifetime. In the code you wrote, you not only borrow the things within MainStruct for 'a, but also MainStruct itself. This is unnecessary since the borrow has an inferred lifetime. You can fix this by removing the 'a in the trait impl
impl<'a> TraitA for &mut MainStruct<'a> {
/*...*/
}
This should do the exact same thing, but removes the bug. The bug is trying to tell you that the code you wrote is buggy, because it borrows MainStruct using a lifetime in the struct itself.

Related

What difference between Self and the struct name produces this error?

This code works fine:
#[derive(Debug)]
struct Foo<'a> {
data: Vec<&'a str>,
}
impl Foo<'_> {
fn bar_func(arg1: &str) {
let f = Foo { data : arg1.split_whitespace().collect() };
println!("{:?}", f.data);
}
}
fn main() {
Foo::bar_func(&"hey split me!");
}
But if I change Foo for Self when creating the struct:
fn bar_func(arg1: &str) {
let f = Self { data : arg1.split_whitespace().collect() };
println!("{:?}", f.data);
}
I get a lifetime error:
error: lifetime may not live long enough
--> src/main.rs:9:31
|
6 | impl Foo<'_> {
| -- lifetime `'2` appears in the `impl`'s self type
7 |
8 | fn bar_func(arg1: &str) {
| - let's call the lifetime of this reference `'1`
9 | let f = Self { data : arg1.split_whitespace().collect() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
= note: requirement occurs because of the type `SplitWhitespace<'_>`, which makes the generic argument `'_` invariant
= note: the struct `SplitWhitespace<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Until now I assumed that these would be interchangeable, and I tend to use Self most of the time, so you can imagine, this got me stuck for a very long time, and it was just luck how I found that it worked fine with the struct name when trying to isolate the problem in a minimal example.
Are they not equivalent, and if so, what is the difference?
They're not the same.
Foo is Foo<'_>, with inferred (or elided) lifetime, and that means we can use the lifetime of arg1.
Self, however, keeps generic parameters of the current type, and that includes lifetimes. Thus, the lifetime of Foo with Self refer to the elided '_ in impl Foo<'_>, which is a distinct generic lifetime that is incompatible with arg1's lifetime.

Why does a trait on a reference raise "cannot borrow as mutable because it is also borrowed as immutable" when a trait on an object does not?

Consider a function
fn clear_non_empty<T>(collection: &mut Vec<T>) {
if !collection.is_empty() {
collection.clear()
}
}
it compiles just fine, and if I try to generalize it for some collection
trait IsEmpty {
fn is_empty(&self) -> bool;
}
trait Clear {
fn clear(&mut self);
}
fn clear_non_empty<'a, Collection: Clear + IsEmpty>(collection: &'a mut Collection) {
if !collection.is_empty() {
collection.clear()
}
}
I also have no problems. But if I change traits to
trait IsEmpty {
fn is_empty(self) -> bool;
}
trait Clear {
fn clear(self);
}
fn clear_non_empty<'a, Collection>(collection: &'a mut Collection)
where
&'a mut Collection: Clear,
&'a Collection: IsEmpty,
{
if !collection.is_empty() {
collection.clear()
}
}
I'm getting
error[E0502]: cannot borrow `*collection` as mutable because it is also borrowed as immutable
--> src/lib.rs:15:9
|
9 | fn clear_non_empty<'a, Collection>(collection: &'a mut Collection)
| -- lifetime `'a` defined here
...
14 | if !collection.is_empty() {
| ---------------------
| |
| immutable borrow occurs here
| argument requires that `*collection` is borrowed for `'a`
15 | collection.clear()
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
which I do not understand, why traits with methods accepting references to self work and traits implemented for references with methods accepting self do not?
The problem is with the way you've declared the lifetime you want to use:
fn clear_non_empty<'a, Collection>(collection: &'a mut Collection)
where
&'a mut Collection: Clear,
&'a Collection: IsEmpty,
{
if !collection.is_empty() {
collection.clear()
}
}
You've given clear_non_empty a lifetime parameter. This means that it's a lifetime the caller can pick, and also that it outlives the entire clear_non_empty function call (because in nearly all cases that's a practical requirement for the function to be able to use the lifetime). But that's not what you need — you need two lifetimes (one for calling is_empty() and one for calling clear()) that do not overlap, so that they do not conflict.
Lifetime parameters can't do this, but you don't actually need a lifetime parameter. What clear_non_empty needs to know is: “if I take a borrow of Collection, will it implement Clear?” And Rust in fact has a syntax for this (having the somewhat esoteric name of “higher-rank trait bounds”, or HRTB):
fn clear_non_empty<Collection>(collection: &mut Collection)
where
for<'a> &'a mut Collection: Clear,
for<'b> &'b Collection: IsEmpty,
{
if !collection.is_empty() {
collection.clear()
}
}
(Syntax note: for<'a> is introducing a lifetime for the following bound only, so each bound could use the same name; I wrote for<'b> just to highlight that they are distinct.)
Notice that the collection parameter no longer has a lifetime — that's also important, because when we call collection.clear() we're not passing the reference we got to it, we're passing an implicit reborrow with a shorter lifetime, so that it doesn't conflict with the borrow for is_empty. The new lifetime annotations accurately reflect what we're doing with collection, rather than requiring longer lifetimes.
The reason you don't have to worry about this when writing traits like trait Clear { fn clear(&mut self); } is because the lifetime quantification — "for any lifetime 'a, we can clear &'a mut Self" — is implicit in the function signature of Clear::clear, which could be written explicitly as fn clear<'a>(&'a mut self);. it is normal that functions from a trait can be called with lifetimes shorter than any constraint on the implementor of the trait.
I thought this could perhaps be solved by using separate lifetimes for IsEmpty and Clear, like so:
trait IsEmpty {
fn is_empty(self) -> bool;
}
trait Clear {
fn clear(self);
}
fn clear_non_empty<'is_empty, 'clear, Collection>(collection: &'clear mut Collection)
where
Collection: 'clear + 'is_empty,
&'clear mut Collection: Clear,
&'is_empty Collection: IsEmpty,
{
if !collection.is_empty() {
collection.clear()
}
}
However this still runs into:
error: lifetime may not live long enough
--> src/lib.rs:15:9
|
9 | fn clear_non_empty<'is_empty, 'clear, Collection>(collection: &'clear mut Collection)
| --------- ------ lifetime `'clear` defined here
| |
| lifetime `'is_empty` defined here
...
15 | if !collection.is_empty() {
| ^^^^^^^^^^^^^^^^^^^^^ argument requires that `'clear` must outlive `'is_empty`
|
= help: consider adding the following bound: `'clear: 'is_empty`
Here we see that the compiler is convinced that 'clear must outlive 'is_empty, while instead we require that these lifetimes do not overlap. But if these lifetimes do not overlap, then how can we turn our mutable reference into an immutable one for the duration of the call to is_empty?
It could be we are running into a limitation of the borrow checker, but let's give it some help and try to separate 'clear and is_empty a bit more:
trait IsEmpty {
fn is_empty(self) -> bool;
}
trait Clear {
fn clear(self);
}
fn clear_non_empty<'is_empty, 'clear, 'input, Collection>(collection: &'input mut Collection)
where
'input: 'clear + 'is_empty,
&'clear mut Collection: Clear,
&'is_empty Collection: IsEmpty,
{
if !collection.is_empty() {
collection.clear()
}
}
It does not help:
error[E0502]: cannot borrow `*collection` as mutable because it is also borrowed as immutable
--> src/lib.rs:16:9
|
9 | fn clear_non_empty<'is_empty, 'clear, 'input, Collection>(collection: &'input mut Collection)
| --------- lifetime `'is_empty` defined here
...
15 | if !collection.is_empty() {
| ---------------------
| |
| immutable borrow occurs here
| argument requires that `*collection` is borrowed for `'is_empty`
16 | collection.clear()
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
At this point I am pretty confident that this is indeed a borrow checker limitation, although I am not sure whether this is a bug or a feature.
If I were you I would open an issue on the Rust repository to get some expert help.

Shared &str along multiple structs conflicts with Lifetimes

I have the following code:
pub trait Regex: RegexClone {
fn check(&self) -> Result<u32,(/* errors should detail where it fails*/)>;
fn next(&self) -> Option<Box<dyn Regex>>;
}
pub trait RegexClone {
fn regex_clone(&self) -> Box<dyn Regex>;
}
pub struct PatternAnyCharacter<'a>{
string: &'a str
}
impl RegexClone for PatternAnyCharacter<'_> {
fn regex_clone(&self) -> Box<dyn Regex> {
return Box::new(PatternAnyCharacter {string: self.string})
}
}
impl Regex for PatternAnyCharacter<'_> {
fn check(&self) -> Result<u32, ()> {
if self.string.len() > 0 {
return Ok(1);
}
Err(())
}
fn next(&self) -> Option<Box<dyn Regex>> {
None
}
}
The idea is that when i call regex_clone i get a new Box<dyn Regex> with the same &str as member, i supossed that since im only using inmutable references when calling regex_clone it would give me a new struct with the same string slice, since is a reference im not moving anything, however the compiler complains the following:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/lib.rs:63:25
|
63 | return Box::new(PatternAnyCharacter {string: self.string})
| ^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
--> src/lib.rs:61:41
|
61 | impl RegexClone for PatternAnyCharacter<'_> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:63:54
|
63 | return Box::new(PatternAnyCharacter {string: self.string})
| ^^^^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the types are compatible
--> src/lib.rs:63:16
|
63 | return Box::new(PatternAnyCharacter {string: self.string})
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Box<(dyn Regex + 'static)>`
found `Box<dyn Regex>`
How can i solve this so i can share the same string slice with multiple struct?
i thought about foregoing the string slice as member entirely and passing it as parameter to check, but hopefully i can avoid it.
You need to define at the trait that the returned dyn Regex can't outlive &self if you want to allow it to borrow from parts of &self.:
pub trait RegexClone {
fn regex_clone<'a>(&'a self) -> Box<dyn Regex + 'a>;
}
(You can also use an anonymous lifetime (Box<dyn Regex + '_>), but this is easier to understand.)
Side note: I don't think "clone" is the right name for such a function.

Can I limit the lifetime pollution from a struct?

I have a struct which contains some stuff. I implement the Iterator trait for that struct, and return a tuple of references to internal data in the struct. That necessitates that I annotate at least some things with lifetimes. What I want is to minimize the lifetime annotation, especially when it comes to other structs which have the original struct as a member.
some code:
pub struct LogReader<'a> {
data:String,
next_fn:fn(&mut LogReader)->Option<(&'a str,&'a [ConvertedValue])>,
//...
}
pub struct LogstreamProcessor {
reader: LogReader, // doesn't work without polluting LogstreamProcessor with lifetimes
//...
}
impl<'a> Iterator for LogReader<'a > {
type Item = (&'a str,&'a[ConvertedValue]);
fn next(&mut self) -> Option<(&'a str,&'a[ConvertedValue])>{(self.next_fn)(self)}
}
impl <'a> LogReader<'a> {
pub fn new(textFile:Option<bool>) -> LogReader<'a> {
LogReader {
next_fn:if textFile.unwrap_or(false) { LogReader::readNextText }else{ LogReader::readNextRaw },
data: "blah".to_string()
}
}
fn readNextText(&mut self)->Option<(&str,&[ConvertedValue])>{unimplemented!();}
fn readNextRaw(&mut self)->Option<(&str,&[ConvertedValue])>{unimplemented!();}
}
Can I limit the lifetime pollution from a struct?
Generically, if you're using them in any of your struct's fields, then you can't. They are made explicit for very good reasons (see Why are explicit lifetimes needed in Rust?), and once you have a struct containing objects that require explicit lifetimes, then they must be propagated.
Note that usually this isn't a concern to consumers of the struct, since the concrete lifetimes are then imposed by the compiler:
struct NameRef<'a>(&'a str);
let name = NameRef("Jake"); // 'a is 'static
One could also slightly mitigate the "noise" on the implementation of next by using the definition of Self::Item.
impl<'a> Iterator for LogReader<'a > {
type Item = (&'a str,&'a[ConvertedValue]);
fn next(&mut self) -> Option<Self::Item> {
(self.next_fn)(self)
}
}
However, your concern actually hides a more serious issue: Unlike you've mentioned, the values returned from next are not necessarily internal data from the struct. They actually live for as long as the generic lifetime 'a, and nothing inside LogReader is actually bound by that lifetime.
This means two things:
(1) I could pass a function that gives something completely different, and it would work just fine:
static NO_DATA: &[()] = &[()];
fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> {
Some(("wat", NO_DATA))
}
(2) Even if I wanted my function to return something from the log reader's internal data, it wouldn't work because the lifetimes do not match at all. Let's try it out anyway to see what happens:
static DATA: &[()] = &[()];
fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> {
Some((&reader.data[0..4], DATA))
}
fn main() {
let mut a = LogReader {
data: "This is DATA!".to_owned(),
next_fn: my_next_fn
};
println!("{:?}", a.next());
}
The compiler would throw you this:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:26:12
|
26 | Some((&reader.data[0..4], DATA))
| ^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 25:88...
--> src/main.rs:25:89
|
25 | fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> {
| _________________________________________________________________________________________^ starting here...
26 | | Some((&reader.data[0..4], DATA))
27 | | }
| |_^ ...ending here
note: ...so that reference does not outlive borrowed content
--> src/main.rs:26:12
|
26 | Some((&reader.data[0..4], DATA))
| ^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the body at 25:88...
--> src/main.rs:25:89
|
25 | fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> {
| _________________________________________________________________________________________^ starting here...
26 | | Some((&reader.data[0..4], DATA))
27 | | }
| |_^ ...ending here
note: ...so that expression is assignable (expected std::option::Option<(&'a str, &'a [()])>, found std::option::Option<(&str, &[()])>)
--> src/main.rs:26:5
|
26 | Some((&reader.data[0..4], DATA))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...where the anonymous lifetime #1 is the log reader's lifetime. Forcing &mut LogReader to also have a lifetime 'a (&'a mut LogReader<'a>) would lead to further lifetime issues when attempting to implement Iterator. This basically narrows down to the fact that 'a is incompatible with references to values of LogReader themselves.
So, how should we fix that?
but that doesn't change the fact that the return type has references and so lifetime annotations come into it
Although that is not accurate (since lifetime elision can occur in some cases), that gives a hint to the solution: either avoid returning references at all or delegate data to a separate object, so that 'a can be bound to that object's lifetime. The final part of the answer to your question is in Iterator returning items by reference, lifetime issue.

Cannot infer an appropriate lifetime for lifetime parameter cloning trait object

The duplicates of this question don't seem to solve things for me. The following code gives me errors:
use std::collections::HashMap;
use std::thread;
pub trait Spider : Sync + Send {
fn add_request_headers(&self, headers: &mut Vec<String>);
}
pub struct Google {}
impl Spider for Google {
fn add_request_headers(&self, headers: &mut Vec<String>) {
headers.push("Hello".to_string())
}
}
fn parallel_get(spiders: &HashMap<String, Box<Spider>>) -> std::thread::JoinHandle<()> {
let thread_spiders = spiders.clone();
thread::spawn(move || {
let headers = &mut vec![];
let spider = thread_spiders.get("Google").unwrap();
spider.add_request_headers(headers);
})
}
fn main() {
let spiders = HashMap::new();
let spider = Box::new(Google{});
spiders.insert("Google", spider);
}
Run on the playground here.
I get:
rustc 1.14.0 (e8a012324 2016-12-16)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> <anon>:18:34
|
18 | let thread_spiders = spiders.clone();
| ^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 17:87...
--> <anon>:17:88
|
17 | fn parallel_get(spiders: &HashMap<String, Box<Spider>>) -> std::thread::JoinHandle<()> {
| ^
note: ...so that types are compatible (expected &&std::collections::HashMap<std::string::String, Box<Spider>>, found &&std::collections::HashMap<std::string::String, Box<Spider + 'static>>)
--> <anon>:18:34
|
18 | let thread_spiders = spiders.clone();
| ^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure#<anon>:19:19: 23:6 thread_spiders:&std::collections::HashMap<std::string::String, Box<Spider>>]` will meet its required lifetime bounds
--> <anon>:19:5
|
19 | thread::spawn(move || {
| ^^^^^^^^^^^^^
I think it's telling me that it can't automatically infer the lifetime of thread_spiders because it needs to be 'static to live long enough for the thread, but it can't outlive 'a which is the lifetime of the input parameter.
The thing is, I can clone other objects in parallel_get and they get moved into the new thread without issue. But for some reason thread_spiders seems to trip up the compiler. It should have a lifetime of 'a if I'm correct and then get moved into the thread closure.
I've tried adding explicit lifetime parameters to parallel_get but haven't been able to get anything working. How can I make this code compile?
The error message is quite confusing in this case, but notice a double ampersand here:
(expected &&std::collections::HashMap<std::string::String, Box<Spider>>, found &&std::collections::HashMap<std::string::String, Box<Spider + 'static>>).
It looks like it tries to clone the reference. I assume you wanted to clone the entire HashMap. Calling clone explicitly as Clone::clone(spiders) gives much clearer error message:
error[E0277]: the trait bound `Spider: std::clone::Clone` is not satisfied
error[E0277]: the trait bound `Spider: std::marker::Sized` is not satisfied
--> error_orig.rs:19:26
|
19 | let thread_spiders = Clone::clone(spiders);
| ^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `Spider`
|
= note: `Spider` does not have a constant size known at compile-time
= note: required because of the requirements on the impl of `std::clone::Clone` for `Box<Spider>`
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::collections::HashMap<std::string::String, Box<Spider>>`
= note: required by `std::clone::Clone::clone`
You are calling Clone::clone on Box<Spider>, an owned trait object.
How do I clone a HashMap containing a boxed trait object? illustrates that it can be implemented by introducing a cloning method to your trait, like so:
pub trait Spider: Sync + Send {
fn add_request_headers(&self, headers: &mut Vec<String>);
fn clone_into_box(&self) -> Box<Spider>;
}
impl Clone for Box<Spider> {
fn clone(&self) -> Self {
self.clone_into_box()
}
}
#[derive(Clone)]
pub struct Google {}
impl Spider for Google {
fn add_request_headers(&self, headers: &mut Vec<String>) {
headers.push("Hello".to_string())
}
fn clone_into_box(&self) -> Box<Spider> {
Box::new(self.clone())
}
}
How to clone a struct storing a trait object? suggests creating a separate trait for this polymorphic cloning method.

Resources