Lifetime gets smaller after extracting method - rust

I had a lifetime problem on extracting a method in Rust. Following is a minimal example:
pub struct Obj {
value: usize,
}
pub struct Container<'a> {
content: &'a Obj,
}
pub struct Props<'a> {
att: Container<'a>,
}
impl <'a> Props<'a> {
pub fn value(&self) -> usize {
self.att.content.value
}
}
This works fine with:
pub fn test<'a>(properties: Props<'a>) -> impl (Fn() -> usize) + 'a {
|| properties.att.content.value
}
but gives an error for:
pub fn test<'a>(properties: Props<'a>) -> impl (Fn() -> usize) + 'a {
|| properties.value()
}
closure may outlive the current function, but it borrows 'properties', which is owned by the current function
I think I understand this error message, but I do not understand why the first piece of code does compile. Isn't properties borrowed also in the first example?
Could this problem be solved by putting some lifetimes to the function value()?
Link to Rust Playground Example

Since edition 2021 closures are allowed to borrow only part of a struct so your first example is allowed to borrow only part of it namely properties.att.content.value which is behind a reference of appropriate lifetime for the closure you're returning.
The second example does not see it only needs that part so it has to borrow the full properties, but that is dropped at the end of the function, so you can't return a closure referencing it.
To make the second example work just follow the compilers recommendation, add a move before the closure, that moves properties inside the closure so it can safely be returned.
pub fn test<'a>(properties: Props<'a>) -> impl (Fn() -> usize) + 'a {
move || properties.value()
}

Related

How to make a lifetime constraint "pass through" from object to its grandchild?

I'm doing some experiments with lifetimes and the borrow checker. Imagine this first struct:
struct First {}
impl First {
fn new() -> Self {
Self {}
}
fn second(&self) -> Second {
Second::new(self)
}
fn hello(&self) {
println!("Hello");
}
}
And the second, which has a lifetime constraint that depends on First:
struct Second<'a> {
owner: &'a First,
}
impl<'a> Second<'a> {
fn new(owner: &'a First) -> Self {
Self { owner }
}
fn hello(&self) {
self.owner.hello();
}
}
The code above works perfectly fine: Second is created by First, and it cannot outlive First.
The problem
Now let's modify Second so it can create a third struct, Third:
struct Second<'a> {
owner: &'a First,
}
impl<'a> Second<'a> {
fn new(owner: &'a First) -> Self {
Self { owner }
}
fn third(&self) -> Third {
Third::new(self.owner)
}
fn hello(&self) {
self.owner.hello();
}
}
And Third itself, which also depends on First:
struct Third<'a> {
owner: &'a First,
}
impl<'a> Third<'a> {
fn new(owner: &'a First) -> Self {
Self { owner }
}
fn hello(&self) {
self.owner.hello();
}
}
I would imagine that, when creating an instance of Third, it would depend on First, but that's not the case. Actually Third depends on Second:
fn main() {
let f = First::new();
let t = {
let sss = f.second();
sss.third() // error: sss does not live long enough
};
}
So, how can I make the lifetime constraint "pass through" from First to Third?
Full playground.
Rust has rules how it infers lifetimes for functions: the lifetime elision rules.
And those rules state that:
Each elided lifetime (i.e. a type that should had have a lifetime, but doesn't, like &T that is actually &'a T) in the parameters becomes a distinct lifetime parameter.
If there is exactly one lifetime used in the parameters (elided or not), that lifetime is assigned to all elided output lifetimes.
In method signatures there is another rule
If the receiver has type &Self or &mut Self, then the lifetime of that reference to Self is assigned to all elided output lifetime parameters.
Let's take First::second() as an example. Its signature is:
fn second(&self) -> Second
Or, with all lifetimes explicitly elided (by the way, it is considered a good practice to explictly elide all lifetimes that are not on references, like Second<'_> in this example):
fn second(&'_ self) -> Second<'_>
So according to rule #1 we assign a new lifetime, let's call it 'a, to &self:
fn second<'a>(&'a self) -> Second<'_>
Now, according to rule #3, we pick 'a for Second<'_>:
fn second<'a>(&'a self) -> Second<'a>
That is, we return Second that has the same lifetime as the reference to self.
Now let's apply it to Second::third()...
fn third(&self) -> Third
// Becomes
fn third<'b>(&'b self) -> Third<'b> // Lifetime `'a` is already used
But this is not what we want! We want the resulting Third to depend on the lifetime of our contained First instance, not on the lifetime of &self! So what we really need is to use Third<'a>:
fn third(&self) -> Third<'a> { ... }
Now it works beautifully.
You just need to specify the same lifetime of the inner reference in Second when creating Third:
impl<'a> Second<'a> {
fn new(owner: &'a First) -> Self {
Self { owner }
}
fn third(&self) -> Third<'a> {
Third::new(self.owner)
}
fn hello(&self) {
self.owner.hello();
}
}
Playground
It is the same as when creating Second from first:
impl First {
...
fn second(&self) -> Second {
Second::new(self)
}
...
}
Here, second is bound to a 'self lifetime, that is, it can live as much as that &self First instance. But in this case the compiler specify it for you.

Create wrapper over a mutable reference with `Copy`-like semantics [duplicate]

This question already has answers here:
Is it possible to create a wrapper around an &mut that acts like an &mut
(1 answer)
Why is the mutable reference not moved here?
(4 answers)
Closed 2 years ago.
I've been adapting some old code I wrote, one of them had the following (simplified):
pub fn a(x: &mut i32) {
for i in 0..10 {
b(x);
}
}
pub fn b(_x: &mut i32) {
}
which worked fine, even though &mut i32 isn't Copy.
I wanted to restrict what methods could be called on the underlying type, (as instead of &mut i32 I had something along the lines of &mut Vec<...>), so I created a wrapper type over the mutable reference:
#[derive(Debug)]
pub struct I32RefMut<'a>(&'a mut i32);
And I attempted to rewrite a and b using this wrapper as follows:
pub fn a2(x: I32RefMut) {
for _i in 0..10 {
b2(x);
}
}
pub fn b2(_x: I32RefMut) {
}
This gives the following error
17 | pub fn a2(x: I32RefMut) {
| - move occurs because `x` has type `I32RefMut<'_>`, which does not implement the `Copy` trait
18 | for _i in 0..10 {
19 | b2(x);
| ^ value moved here, in previous iteration of loop
Playground link
Which is understandable, as x gets moved into b2 on the first iteration of the loop.
Unfortunately I cannot implement Clone nor Copy, as there may only be 1 mutable reference to the object at a time.
My question is how does &mut i32 work around this and how can I implement this workaround (or similar) on my type I32RefMut.
If possible I'd like to avoid unsafe code as much as possible, such as using #[repr(transparent)] struct I32Wrapper(i32) and then transmuting &mut i32 to &mut I32Wrapper, unless a safe wrapper of this type of operation exists already.
EDIT:
Found a "hack" solution, but I'm not very happy about how it looks, so I'll leave the question open. If no other solutions are found, I'll post it as an answer.
If the call to b2 is changed to b2( I32RefMut(x.0) ), then it successfully compiles. This however, cannot be generalised to a function as such:
impl<'a> I32RefMut<'a> {
pub fn my_clone<'b: 'a>(&'b mut self) -> I32RefMut<'b> {
I32RefMut( self.0 )
}
}
As when we try to call it the compiler tells us we can't borrow x mutably twice.
As this wrapper type is supposed to be defined in a library, I cannot expose it's internal reference, as the whole point of the wrapper was to restrain what the user can call on the reference.
The thing is that you are taking ownership of your new type instance when calling b. Just take a reference to your type instead to get access to the underlaying type:
pub fn a2(x: &I32RefMut) {
for _i in 0..10 {
b2(x);
}
}
pub fn b2(_x: &I32RefMut) {
}
Playground
Actually if you want to mutate it you need to play around a bit with them:
pub fn a2(mut x: I32RefMut) {
for _i in 0..10 {
b2(&mut x);
}
}
pub fn b2(_x: &mut I32RefMut) {
*(_x.0) += 1
}
Playground

Return reference with lifetime of self

I'd like to write some code like the following:
struct Foo {
foo: usize
}
impl Foo {
pub fn get_foo<'a>(&'a self) -> &'self usize {
&self.foo
}
}
But this doesn't work, failing with invalid lifetime name: 'self is no longer a special lifetime.
How can I return a reference that lives as long as the object itself?
You don't want the reference to live exactly as long as the object. You just want a borrow on the object (quite possibly shorter than the entire lifetime of the object), and you want the resulting reference to have the lifetime of that borrow. That's written like this:
pub fn get_foo<'a>(&'a self) -> &'a usize {
&self.foo
}
Additionally, lifetime elision makes the signature prettier:
pub fn get_foo(&self) -> &usize {
&self.foo
}
In your example the lifetime of self is 'a so the lifetime of the returned reference should be 'a:
pub fn get_foo<'a>(&'a self) -> &'a usize {
&self.foo
}
However the compiler is able to deduce (lifetime elision) the correct lifetime in simple cases like that, so you can avoid to specify lifetime at all, this way:
pub fn get_foo(&self) -> &usize {
&self.foo
}
Look here for lifetime elision rules

Lifetime error for returned value of a function

This is a simplified version of a piece of code I am trying to implement:
struct FirstStruct
{
a: i8,
}
impl FirstStruct
{
fn get(&self) -> Option<&str>
{
Some("aaa")
}
}
pub struct SecondStruct<'a>
{
pub name: Option<&'a str>,
}
impl<'a> SecondStruct<'a>
{
fn extract_string(obj: &/*'a*/ FirstStruct) -> Option<&'a str>
{
obj.get() //this is where the error happen
}
pub fn from_string() -> SecondStruct<'a>
{
let obj = FirstStruct{a: 1};
SecondStruct{
name: SecondStruct::extract_string(&obj),
}
}
}
fn main()
{
let g_def_res = SecondStruct::from_string();
}
This code throws the following error :
test2.rs:23:13: 23:18 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
test2.rs:23 obj.get() //this is where the error happen
^~~~~
test2.rs:21:5: 24:6 help: consider using an explicit lifetime parameter as shown: fn extract_string(obj: &'a FirstStruct) -> Option<&'a str>
test2.rs:21 fn extract_string(obj: &FirstStruct) -> Option<&'a str>
test2.rs:22 {
test2.rs:23 obj.get() //this is where the error happen
test2.rs:24 }
error: aborting due to previous error
Applying the proposed solution throw this error :
test2.rs:30:55: 30:58 error: `obj` does not live long enough
test2.rs:30 name: SecondStruct::extract_string(&obj),
^~~
test2.rs:27:5: 32:6 note: reference must be valid for the lifetime 'a as defined on the block at 27:4...
test2.rs:27 {
test2.rs:28 let obj = FirstStruct{a: 1};
test2.rs:29 SecondStruct{
test2.rs:30 name: SecondStruct::extract_string(&obj),
test2.rs:31 }
test2.rs:32 }
test2.rs:28:37: 32:6 note: ...but borrowed value is only valid for the block suffix following statement 0 at 28:36
test2.rs:28 let obj = FirstStruct{a: 1};
test2.rs:29 SecondStruct{
test2.rs:30 name: SecondStruct::extract_string(&obj),
test2.rs:31 }
test2.rs:32 }
error: aborting due to previous error
To summarise:
How to say that the return value of FirstStruct::get must have the lifetime of either [the return value of SecondStruct::from_str | the struct lifetime 'a]? I think both refer to same thing?
pub fn from_string() -> SecondStruct<'a> {
let obj = FirstStruct { a: 1 };
SecondStruct {
name: SecondStruct::extract_string(&obj),
}
}
This code says "I will return a SecondStruct with the lifetime 'a". The caller of the code gets to determine what the length of the lifetime 'a is. This is almost never what you want!
// Lifetime elision means the method is equivalent to this
// fn get<'a>(&'a self) -> Option<&'a str>
fn get(&self) -> Option<&str> {
Some("aaa")
}
This code uses says that the string returned will live as long as self lives.
Put these two concepts together, and you can understand your error. The variable obj is only defined to live as long as the function call is active. However, you are trying to return a reference to the inner-workings of the struct beyond the call! Actually, you are trying to return it for any arbitrary lifetime the caller decides! This is Rust preventing you from shooting yourself in the foot, hooray for Rust!
So how do you fix your problem? For the provided example code, the easiest thing is to just use the 'static lifetime:
struct FirstStruct { a: i8 }
impl FirstStruct {
fn get(&self) -> Option<&'static str> { Some("aaa") }
}
pub struct SecondStruct<'a> { name: Option<&'a str> }
impl<'a> SecondStruct<'a> {
fn extract_string(obj: &FirstStruct) -> Option<&'static str> { obj.get() }
pub fn from_string() -> SecondStruct<'static> {
let obj = FirstStruct { a: 1 };
SecondStruct { name: SecondStruct::extract_string(&obj) }
}
}
fn main() {
let g_def_res = SecondStruct::from_string();
}
But that's probably not what you really want. The next thing to try would be to embed FirstStruct inside SecondStruct, and simply delegate to it. Another option would be to move from &str to String - String owns the string data, and so you can transfer ownership from First to Second.
Whatever you do, you have to ensure that the source of the string data outlives the function call to from_string.
Either the return value of FirstStruct::get has been allocated on the stack or it has been allocated on the heap.
It's trickier than that. The return value is always on the stack. That is, the Option<&str> takes up space on the stack. The &str may contain a pointer to something that is allocated either on the stack or heap, it's not known by this code. All you know is that the pointed-at value is guaranteed to live for the lifetime of that specific FirstStruct item.
You don't own the string, so you can't transfer ownership around.
I can't move FirstStruct because it is from another library (rustc-serialize
I'm not sure what you mean. If you have an object, then you can embed it into your object. The fact that it comes from another crate doesn't come into play. If you have a reference to something, then you can still capture the reference, but then your object has to live for a shorter period than the reference (so that it never becomes invalid).
Unwrapping Option, updating to a string and rewrapping in Option is a lot of boilerplate.
Have you seen Option::map? It makes this kind of thing very succinct. Combined with From, you can write a very short thing to convert an Option<&str> to Option<String>:
// fn is just to establish some types, you'd just use the `.map` call in real code
fn foo(a: Option<&str>) -> Option<String> {
a.map(From::from)
}

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