Borrow mutable reference in an impl block with generic lifetime parameter - rust

I'm trying to write a simple code which generates elements based on a random number generator, for which I have a working code here. Now I wanted to add a reference from each struct to the next in the list. The basic idea is that each struct has a state and an optional reference to another struct with the same lifetime.
#[derive(Copy, Clone, Debug)]
enum MyState
{
On,
Off
}
#[derive(Copy, Clone, Debug)]
struct MyStruct<'a>
{
state: MyState,
next_struct : Option<&'a MyStruct<'a>>,
}
The generic lifetime parameter 'a is a new addition to basically mark the fact that all structs have the same lifespan.
Then I have a simple associated function creating random structs with no reference, but now my impl block must also have the generic lifetime parameter.
// stand-in for replacement struct from rand crate
struct RandomGenerator {
random_number : f64,
}
impl<'a> MyStruct<'a>
{
fn random(r : & mut RandomGenerator) -> MyStruct
{
if r.random_number > 0.5 {
r.random_number -= 0.1;
return MyStruct{state : MyState::On, next_struct : None};
}
r.random_number = 1.0 as f64;
MyStruct{state : MyState::Off, next_struct : None}
}
}
Finally I'm trying to generate my elements in a loop
fn main() {
let mut grid = Vec::<MyStruct>::new();
let mut rng = RandomGenerator{random_number : 0.5};
for _i in 0..GRID_SIZE*GRID_SIZE // const GRID_SIZE : usize = 10;
{
grid.push(MyStruct::random(&mut rng));
}
println!("{:#?}", grid);
}
The full code is here. While the first version worked as expected, the second version fails to compile with
error[E0499]: cannot borrow `rng` as mutable more than once at a time
--> src/main.rs:43:60
|
43 | grid.get_mut(i).unwrap().push(MyStruct::random(&mut rng));
| ^^^^^^^^ `rng` was mutably borrowed here in the previous iteration of the loop
error: aborting due to previous error
Looking at similar questions most of them deal with self references, which seems to be more complicated than what I'm doing here, since I'm passing an unrelated object just for one function call, and it appears to be burrowed for longer..
I tried adding a generic lifetime 'b to the random method, which is then used only for the RNG mutable, but this does not work either. Why would adding a generic lifetime parameter that is not even used in the signature of the function changes the borrowing behaviour? What is the correct way to write this?

Here's a working version of your function (playground):
impl<'a> MyStruct<'a>
{
fn random(r: &mut RandomGenerator) -> MyStruct<'a>
{ // ^^^^
This is due to lifetime elision:
If there is exactly one input lifetime position (elided or not), that lifetime is assigned to all elided output lifetimes.
Since you didn't annotate the lifetime tied to MyStruct, the compiler inferred it must be linked to the lifetime of r.

Related

Rust lifetime confusion with custom clone function

I think there is a subtle issue with what I'm trying to do here but I can't quite figure out why. I am attempting to clone a Box type (I know the type inside) but I think the lifetime is being propagated out somehow.
struct Thing
{
internal:Box<dyn std::any::Any>
}
impl Thing
{
fn new<T:'static>(u:usize) -> Self
{
return Self
{
internal:Box::new(u)
}
}
fn clone_func<T:'static>(&self) -> Self
{
return Self
{
internal:Box::new(self.internal.downcast_ref::<T>().unwrap().clone())
}
}
}
pub fn main()
{
let a = Thing::new::<usize>(12usize);
let b = a.clone_func::<usize>();
}
Error
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> <source>:19:45
|
15 | fn clone_func<T:'static>(&self) -> Self
| ----- this data with an anonymous lifetime `'_`...
...
19 | internal:Box::new(self.internal.downcast_ref::<T>().unwrap().clone())
| -----------------------^^^^^^^^^^^^------------------------- ...is captured and required to live as long as `'static` here
error: aborting due to previous error
The problem is that you didn't request T to be Clone, so when you called self.internal.downcast_ref::<T>().unwrap().clone(), you actually cloned the reference, and tried to box it1.
Boxing &T works as far as the types are concerned (because it's a Box<dyn Any>), but it fails borrow checking. While T is guaranteed not to contain references to non-static data, the &T refers to the data inside &self which is not 'static, but has the anonymous lifetime of &self. This is actually pointed out by the compiler, but the error doesn't make sense without context.
Simply changing the trait bound to T: Clone + 'static makes the example compile:
fn clone_func<T: Clone + 'static>(&self) -> Self {
return Self {
internal: Box::new(self.internal.downcast_ref::<T>().unwrap().clone()),
};
}
Playground
1
A shared reference is Clone and Copy because once you have one, you're allowed to create more references to the same data. Normally, given a foo: &T and a T: Clone, foo.clone() will resolve to T::clone(foo), which returns a T as expected. But if T isn't Clone, foo.clone() resolves to <&T>::clone(&foo), which returns another &T referring to the same T value as foo, i.e. it "clones" foo itself rather than the intended *foo.
For example, in this snippet, the type of b.clone() is &X, not X (playground):
//#[derive(Clone)]
struct X;
fn main() {
let a = X;
let b = &a;
let () = b.clone(); // note type of b.clone() is &X, not X
}
If you uncomment #[derive(Clone)], the type of b.clone() becomes the expected X.

Lifetime on impl for a string that comes from somewhere else

This whole lifetime thing in Rust is still dark magic for me. I have a general idea of how it works but whenever I have to define lifetimes myself I have a hard time figuring out what to do. Here's what I want to do:
I have a [&str, 100] that comes from a submodule and I want to write a very simple randomized iterator that uses data from this submodule. Here's roughly what I do:
use rand::distributions::{Distribution, Uniform};
use super::data:Data;
struct RandomData {
range: Uniform<usize>,
rng: rand::rngs::ThreadRng,
}
impl RandomData {
fn new () -> RandomData {
RandomData {
range:·Uniform::new(0, Data.len()),
rng: rand::thread_rng(),
}
}
}
impl Iterator for RandomData {
type Item = &str;
fn next(next(&mut self) -> Option<Self::Item> {
let index = self.range.sample(&mut self.rng);
Some(Data[index])
}
}
Now, obviously the compiler is asking for lifetimes here because of the &str and the easiest way would be to simply use a static lifetime &'static str. But I wondered how to do this right, so I tried the real deal.
I started with the following changes to the iterator implementation:
impl<'a> Iterator for RandomData {
type Item = &'a str;
fn next(next(&mut self) -> Option<Self::Item> { .. }
}
Now the compiler says: error[E0207]: the lifetime parameter 'a is not constrained by the impl trait, self type, or predicates and suggest to read more about this error E0207, which I did. I think the gist is, that the lifetime parameter needs to appear either in the Trait or implementing type. Both is not the case because I don't need it there and in this case the documentation suggests to use PhantomData. But it also only talks about types and I don't really get it to work.
If I try to do:
struct RandomData<'a> {
range: Uniform<usize>,
rng: rand::rngs::ThreadRng,
phantom: PhantomData<&'a str>
}
I get a whole new bunch of messages about anonymous lifetimes, so I added them, but then get stuck with:
error[E0106]: missing lifetime specifier --> src/epcs/random_epc.rs:12:22
|
12 | pub fn new () -> RandomEPC {
| ^^^^^^^^^ help: consider giving it a 'static lifetime: `RandomEPC + 'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
and I'm not sure where to go from here.
Edit
Thanks phimuemue for the suggestion. I created a simplified example here:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bddde9310da5cf838dafee83e05cd78a
Lifetime is Rust describe how long will the data live before being drop.
In your case, the item of your Iterator is a reference to the data hold by Data. Therefore its lifetime correspond to the lifetime of Data. If Data is of lifetime static (it will live during the whole life of the process) then the right way to do your impl is to output Item with lifetime `static.
The idea with Associated Types is that the trait should be implemented only once. You can't implement twice Iterator, once with String as Item and once with &'static str. (See the book). Therefore, in your case you should implement Iterator only once with &'static str and not try to implement it for every lifetime 'l with &'l str.

How to infer an appropriate lifetime for an implementation using lifetimes for structs and impl?

How do I resolve this error? What exactly am I telling the compiler when I use the "anonymous lifetime" in impl?
struct LineHandlerInfo<'a> {
label: &'a str,
match_literal: &'a str,
f: fn(&str) -> Option<&str>,
}
struct Game<'a> {
handlers: Vec<LineHandlerInfo<'a>>,
}
impl Game<'_> {
fn match_str<'a>(
&'a mut self,
label: &'a str,
match_literal: &'a str,
mut f: fn(&str) -> Option<&str>,
) {
let mut lh = LineHandlerInfo {
label,
match_literal,
f,
};
self.handlers.push(lh);
}
}
fn main() {
let mut g = Game {
handlers: Vec::new(),
};
g.match_str("echo hello", "hello", |s| {
println!("{}", s);
None
});
}
When I attempt to compile, I get the following error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:18:22
|
18 | let mut lh = LineHandlerInfo {
| ^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the method body at 12:18...
--> src/main.rs:12:18
|
12 | fn match_str<'a>(
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:19:13
|
19 | label,
| ^^^^^
note: but, the lifetime must be valid for the lifetime '_ as defined on the impl at 11:11...
--> src/main.rs:11:11
|
11 | impl Game<'_> {
| ^^
= note: ...so that the expression is assignable:
expected LineHandlerInfo<'_>
found LineHandlerInfo<'_>
How do I resolve this error and what exactly am I telling the compiler when I specify a lifetime on impl Game when I already have a lifetime on the struct?
How do I resolve this error and what exactly am I telling the compiler when I specify a lifetime on impl Game when I already have a lifetime on the struct?
I suspect your confusion stems from an incomplete understanding of the way in which lifetimes are declared and used in Rust.
Struct Lifetimes
In order to use a lifetime on a struct, you declare the lifetime inside the <> adjacent to the name of the struct you are declaring, and then refer to that lifetime inside the struct definition. Importantly, note that the lifetime declared there is scoped to the struct definition - it has no meaning outside.
For example (using the MRE that #Shepmaster provided):
struct Game<'a> {
handlers: Vec<&'a str>,
}
The struct Game contains a vector of references to strings, and the strings which are referenced must last at least as long as the Game struct.
Impl Lifetimes
When using a lifetime specifier on an impl block, you declare the lifetime inside the <> adjacent to the impl keyword, after which you may refer to the lifetime both in the struct being implemented, and inside the implementation itself, like this:
impl<'b> Game<'b> {
fn match_str(&mut self, label: &'b str) {
self.handlers.push(label);
}
}
Note that I am using an entirely different lifetime name here ('b) to illustrate that the the lifetime declaration on the struct is independent of the one on the impl block.
Breaking this down:
impl<'b>
This means that we are defining an implementation for a struct, and within that definition we will use the lifetime 'b
Game<'b> {
This means that the impl is for the struct Game with lifetime 'b - so any references to self inside this implementation are going to automatically have lifetime 'b as well.
fn match_str(&mut self, label: &'b str) {
Here we define the method match_str which takes an argument label. label is a string slice which also has the lifetime 'b - so it must last at least as long as the self that the method is called on.
In your original code, you had something like this:
impl Game<'_> {
fn match_str<'a>(&mut self, label: &'a str) {
...
}
}
This was telling the compiler:
That you are starting a new impl block that, and there are no lifetimes declared at impl level
That the implementation is for the struct Game; this struct has a lifetime parameter but we don't care about it and we are not going to tie it to any element of the implementation
We are defining a method match_str, and we are declaring a lifetime 'a which we can refer to in the rest of the function signature
We have an argument label which has the lifetime a, but we aren't relating this lifetime to anything else
More information:
Rust Book - Lifetime Annotations in Struct Definitions
Rust Book - Lifetime Annotations in Method Definitions
How do I resolve this error?
Remove the generic lifetime from the function, provide a name for the lifetime on the impl block instead of using the anonymous lifetime, then use the named lifetime in the function arguments. Remove the lifetime from &self:
impl<'a> Game<'a> {
fn match_str(&mut self, label: &'a str, match_literal: &'a str, f: fn(&str) -> Option<&str>) {
self.handlers.push(LineHandlerInfo {
label,
match_literal,
f,
});
}
}
See also:
Cannot borrow as mutable more than once at a time in one code - but can in another very similar
What exactly am I doing when I use the "anonymous lifetime" in impl?
You are effectively stating "I know there's a lifetime here, but I don't care about it". However, that's not true for your case; you do care about the lifetime that parameterizes the type because that's what your variables need to match.
See also:
'_, the anonymous lifetime in the Edition Guide
for a struct with a function pointer in it
This has nothing to do with function pointers. When encountering problems while programing, I recommend creating a minimal, reproducible example, stripping out things that don't make the error go away. This allows you to focus on exactly the problem at hand. For example, this reproduces the same error:
struct Game<'a> {
handlers: Vec<&'a str>,
}
impl Game<'_> {
fn match_str<'a>(&mut self, label: &'a str) {
self.handlers.push(label);
}
}

How does borrowing Box<Trait> contents work?

I have this minimal example code:
use std::borrow::BorrowMut;
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn main() {
let mut encryptor: Box<Foo> = Box::new(Bar);
encrypt(encryptor.borrow_mut());
}
fn encrypt(encryptor: &mut Foo) { }
but it fails with this error:
error: `encryptor` does not live long enough
--> src/main.rs:11:1
|
10 | encrypt(encryptor.borrow_mut());
| --------- borrow occurs here
11 | }
| ^ `encryptor` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
The kind people at #rustbeginners found that I have to dereference the box to get the contents, and then borrow the contents. Like this:
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn main() {
let mut encryptor: Box<Foo> = Box::new(Bar);
encrypt(&mut *encryptor);
}
fn encrypt(encryptor: &mut Foo) { }
It works, but I don't understand it.
Why do I need to dereference first? What is the error trying to say? Normally it isn't an error that a value is dropped at the end of the function.
Apparently it's not just me who doesn't understand how this works; an issue has been filed.
Let's start with a change that allows the code to work:
fn encrypt(encryptor: &mut (Foo + 'static)) { }
The important difference is the addition of + 'static to the trait object - the parens are just needed for precedence.
The important thing to recognize is that there are two lifetimes present in &Foo:
a lifetime for the reference itself: &'a Foo
a lifetime that represents all the references inside the concrete value that the trait abstracts: &(Foo + 'b).
If I'm reading the RFCs correctly, this was introduced by RFC 192, and RFC 599 specified reasonable defaults for the lifetimes. In this case, the lifetimes should expand like:
fn encrypt(encryptor: &mut Foo) { }
fn encrypt<'a>(encryptor: &'a mut (Foo + 'a)) { }
On the other end of the pipe, we have a Box<Foo>. Expanded by the rules of the RFC, this becomes Box<Foo + 'static>. When we take a borrow of it, and try to pass it to the function, we have an equation to solve:
The lifetime inside the trait object is 'static.
The function takes a reference to a trait object.
The lifetime of the reference equals the lifetime of references inside the trait object.
Therefore, the reference to the trait object must be 'static. Uh oh!
The Box will be dropped at the end of the block so it certainly isn't static.
The fix with explicit lifetimes allows the lifetime of the reference to the trait object to differ from the lifetime of the references inside the trait object.
If you needed to support a trait object with internal references, an alternate is to do something like:
fn encrypt<'a>(encryptor: &mut (Foo + 'a)) { }
True credit for this explanation goes to nikomatsakis and his comment on GitHub, I just expanded it a bit.

Unable to infer lifetime for borrow expression when using a trait with an explicit lifetime

use std::io::BufReader;
struct Foo {
buf: [u8, ..10]
}
trait Bar<'a> {
fn test(&self, arg: BufReader<'a>) {}
}
impl<'a, T: Bar<'a>> Foo {
fn bar(&'a mut self, t: T) {
t.test(BufReader::new(&self.buf));
let b = &mut self.buf;
}
fn baz(&self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
fn main() {}
The code above fails to compile, with the error message:
lifetimes.rs:17:31: 17:40 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
lifetimes.rs:17 t.test(BufReader::new(&self.buf));
^~~~~~~~~
lifetimes.rs:16:5: 18:6 help: consider using an explicit lifetime parameter as shown: fn baz(&'a self, t: T)
lifetimes.rs:16 fn baz(&self, t: T) {
lifetimes.rs:17 t.test(BufReader::new(&self.buf));
lifetimes.rs:18 }
error: aborting due to previous error
However, if I add the named lifetime parameter, I cannot mutable borrow the buf field after calling test, as seen in fn bar. Commenting out the fn baz and trying to compile results in:
lifetimes.rs:13:22: 13:30 error: cannot borrow `self.buf` as mutable because it is also borrowed as immutable
lifetimes.rs:13 let b = &mut self.buf;
^~~~~~~~
lifetimes.rs:12:32: 12:40 note: previous borrow of `self.buf` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `self.buf` until the borrow ends
lifetimes.rs:12 t.test(BufReader::new(&self.buf));
^~~~~~~~
lifetimes.rs:14:6: 14:6 note: previous borrow ends here
lifetimes.rs:11 fn bar(&'a mut self, t: T) {
lifetimes.rs:12 t.test(BufReader::new(&self.buf));
lifetimes.rs:13 let b = &mut self.buf;
lifetimes.rs:14 }
^
error: aborting due to previous error
My understanding of this is that by adding the named lifetime 'a to the &'a mut self parameter, the reference taken by BufReader has a lifetime as long as the self reference is valid, which is until the end of the function. This conflicts with the mutable borrow of self.buf on the line after.
However, I am not sure why I need the named lifetime parameter on the self. It seems to me that the BufReader reference should be able to only exist for the lifetime of the t.test method call. Is the compiler complaining because the self.buf borrow must be ensured to live only as long as the &self borrow? How would I go about doing that while still only borrowing it for the lifetime of the method call?
Any help in going about fixing this problem and understanding more about the semantics here would be much appreciated!
Update
So I am still looking into this problem, and I have found this test case and this issue that show basically what I am trying to do. I would very much like to understand why the error pointed to by the test case link is an error.
I can see in the issue rustc output that attempts to point out what the error is, but I am having trouble understanding what exactly it is trying to say.
Removing all explicit lifetimes also works. I've found that I only add lifetimes when I'm sure I need them (i.e. to specifiy that two lifetimes should intersect at a given point which can't be known to the compiler).
I'm not sure exactly what you're going for, but this compiles (on rustc 0.13.0-nightly (cc19e3380 2014-12-20 20:00:36 +0000)).
use std::io::BufReader;
struct Foo {
buf: [u8, ..10]
}
trait Bar {
fn test(&self, arg: BufReader) {}
}
impl<T: Bar> Foo {
fn bar(&mut self, t: T) {
t.test(BufReader::new(&self.buf));
let b = &mut self.buf;
}
fn baz(&self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
Edit
I'm going to copy-edit my comment here:
I originally thought that adding a lifetime or generic parameter to the trait / struct / enum was a shorthand for putting it on every method in the trait, but I was wrong. My current understanding is that you add a lifetime to the trait / struct / enum when that item needs to participate in the lifetime, likely because it is storing a reference with that lifetime.
struct Keeper<'a> {
counts: Vec<&'a i32>,
}
impl<'a> Keeper<'a> {
fn add_one(&mut self, count: &'a i32) {
if *count > 5 {
self.counts.push(count);
}
}
fn add_two<'b>(&mut self, count: &'b i32) -> i32 {
*count + 1
}
}
fn main() {
let mut cnt1 = 1;
let mut cnt2 = 2;
let mut k = Keeper { counts: Vec::new() };
k.add_one(&cnt1);
k.add_two(&cnt2);
// cnt1 += 1; // Errors: cannot assign to `cnt1` because it is borrowed
cnt2 += 1; // Just fine
println!("{}, {}", cnt1, cnt2)
}
Here, we've added a lifetime to Keeper because it might store the reference it is given. The borrow checker must assume that the reference is stored for good when we call add_one, so once we call that method, we can no longer mutate the value.
add_two, on the other hand, creates a fresh lifetime that can only be applied to that function invocation, so the borrow checker knows that once the function returns, it is the One True Owner.
The upshot is, if you need to store a reference, then there's nothing you can do at this level. Rust can't make sure you are safe, and that's something it takes seriously.
However, I bet you don't need to store the reference. Move the <'a, T: Bar<'a>> from the impl to the fn and you'll be good to go.
Said another way: I bet you should never have impl<A> if your trait or struct don't require it. Put the generics on the methods instead.
Original
This compiles, but I'm not 100% sure it does what you intended:
impl Foo {
fn baz<'a, T: Bar<'a>>(&'a self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
I fell into this trap myself, so I'll paste what I was told:
Everything in the impl block is parameterized. I've actually never
seen type parameters added to impl blocks themselves that aren't part
of the trait or type definition. It's far more common to parameterize
the individual methods that need it.
Perhaps other comments / answers can help explain in further detail.

Resources