Rust lifetime confusion with custom clone function - rust

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.

Related

How do I write an enum that has variants of the same type but with different lifetimes, one being 'static?

I'm trying to implement a smart pointer that should be able to reference data of type T either borrowed with the lifetime 'a or borrowed with the lifetime 'static:
pub enum SmartPtr<'a, T: 'a> {
/// Should live as long as this struct or longer - don't know exactly how long, so we need to clone this when we clone the struct
Borrowed(&'a T),
/// Lives forever: So we never need to clone this
/// Fails here with: 'the parameter type `T` may not live long enough'
Static(&'static T),
}
The SmartPtr will also contain other enum fields like Rc and Box (the example above has been simplified). SmartPtr will be mostly used in structs that should be cloneable ... when the input data T (for example a static string) is 'static I don't want to clone the data.
I would like to implement Clone for this:
impl<'a, T> Clone for SmartPtr<'a, T>
where
T: Clone,
{
fn clone(&self) -> Self {
match self {
SmartPtr::Borrowed(value) => {
// here we have to clone the value
SmartPtr::Borrowed(value.clone())
}
SmartPtr::Static(value) => {
// Important: No need to clone, since value is static and lives forever
SmartPtr::Static(value)
}
}
}
}
The compiler fails:
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:7:12
|
2 | pub enum SmartPtr<'a, T: 'a> {
| -- help: consider adding an explicit lifetime bound `T: 'static`...
...
7 | Static(&'static T),
| ^^^^^^^^^^^
|
note: ...so that the reference type `&'static T` does not outlive the data it points at
--> src/main.rs:7:12
|
7 | Static(&'static T),
| ^^^^^^^^^^^
How do I fix this?
Edited
As I wrote in the comment, my SmartPtr makes no sense. But this seems to make sense:
pub enum SmartPtr<T : 'static /* WHY IS 'static REQUIRED HERE? */> where T : ?Sized {
Rc(Rc<T>), // Here 'static makes no sense, it's Rc'd
Boxed(Box<T>), // Here 'static makes no sense, it's owned
Static(&'static T) // Here we need 'static
}
I don't see why the 'static is required in SmartPtr<T : 'static. The SmartPtr<T : 'static defines the lifetime of T for the entire enum, right? But I only need a static lifetime in case Static(&'static T), not for the two cases Rc(Rc<T>) and Boxed(Box<T>) (T is owned in Box<T> - a lifetime makes no sense IMHO).
I don't get it... but it works (but don't see why this works):
#[test]
fn smart_ptr_test() {
// Static string -> Ok, this of course works "hello" is static
let static_string = SmartPtr::Static("hello");
// Boxed vector -> But it's not 'static, why does this work?
let vector = vec!["hello"];
let box_vector = SmartPtr::Boxed(Box::new(vector));
// Rc'd vector -> why does this work?, vector_rc is not static
let vector_rc = Rc::new(vec!["hello"]);
let box_vector = SmartPtr::Rc(vector_rc);
}
Thanks trentcl & Shepmaster. This post http://stackoverflow.com/questions/40053550/the-compiler-suggests-i-add-a-static-lifetime-because-the-parameter-type-may-no helped and things are now clearer (maybe not 100% but clear enough for now).
I made a new example to show why the 'static lifetime makes also sense for the enum case Boxed(Box<T>):
pub enum SmartPtr<T : 'static> where T : ?Sized {
Rc(Rc<T>),
Boxed(Box<T>),
Static(&'static T),
}
struct Bar {
data: Vec<String>,
}
struct Foo<'a> {
data: &'a Vec<String>,
}
#[test]
fn smart_ptr_test_2() {
// Example 1: Does compile: Bar is 'static (since vector is moved)
{
let vec2 = vec!["hello".to_string()];
let bar = Box::new(Bar {
data: vec2
});
let box3 = SmartPtr::Boxed(bar);
}
// Example 2: Does not compile ('a in Foo is inferred to be 'static but in my code it's not)
{
let vec1 = vec!["hello".to_string()];
let foo = Box::new(Foo {
// compiler error: 'note: borrowed value must be valid for the static lifetime'
data: &vec1
});
// when this line is here: the compiler infers lifetime 'a of Foo to be 'static
let box2 = SmartPtr::Boxed(foo);
// <--- life of 'vec1' ends here; it's not 'static since 'vec1' goes out of scope here
}
}

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.

How do I return a boxed closure from a method that has a reference to the struct?

I have a structure that contains a value and I want to obtain a function that operates on this value:
struct Returner {
val: i32,
}
impl<'a> Returner {
fn get(&'a self) -> Box<Fn(i32) -> i32> {
Box::new(|x| x + self.val)
}
}
This fails compilation:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:7:18
|
7 | Box::new(|x| x + self.val)
| ^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 5:1...
--> src/main.rs:5:1
|
5 | impl<'a> Returner {
| ^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected &&Returner
found &&'a Returner
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<std::ops::Fn(i32) -> i32 + 'static>
found std::boxed::Box<std::ops::Fn(i32) -> i32>
This is because the closure borrows self, which is fine by me, because I don't intend to use the obtained function after the struct is destroyed. From what I've gathered so far, there's two ways to make it possible:
Use the move keyword. I don't want to use it because it will take ownership on the object, and want I to use it after it has returned this function.
Explicitly specify the lifetime of the closure to tell the compiler that it has the same lifetime as the struct it was called from.
I think that 2 is the correct way in my situation, but I've not been able to find out how to specify the closure's lifetime. Is there a direct way to do it or I've got it all wrong and it contradicts Rust lifetime logic?
In general, you can specify the lifetime of a boxed trait object by writing Box<Trait + 'a> and analogously for trait objects behind other kinds of pointers (if it's omitted, it defaults to 'static at least in the case of Box). So in this specific case you want the return type Box<(Fn(i32) -> i32) + 'a>.
However, when you do that you will see another error about self not living long enough. The reason is that (without move) the closure will capture a reference to the local variable self. The solution is to use move. This does not move the Returner object, it moves self which is a reference to the Returner object.
In summary:
struct Returner {
val: i32,
}
impl<'a> Returner {
fn get(&'a self) -> Box<Fn(i32) -> i32 + 'a> {
Box::new(move |x| x + self.val)
}
}
As said in an existing answer:
Add a lifetime that ties the lifetime of self to the lifetime of the returned value.
Move the reference to self into the closure.
Since Rust 1.26, you no longer need to return a boxed closure if you are only returning a single type. Instead, you can use impl Trait:
impl Returner {
fn get<'a>(&'a self) -> impl Fn(i32) -> i32 + 'a {
move |x| x + self.val
}
}
See also:
Why is adding a lifetime to a trait with the plus operator (Iterator<Item = &Foo> + 'a) needed?
What is the correct way to return an Iterator (or any other trait)?
Returning a closure from a function
Conditionally iterate over one of several possible iterators

Confusing error in Rust with trait object lifetime

Can anyone tell what the problem is with the following code? The compiler is complaining about lifetimes, but the error message makes absolutely no sense. I've tried everything I could think of, but nothing seems to help.
use std::borrow::BorrowMut;
trait Trait<'a> {
fn accept(&mut self, &'a u8);
}
struct Impl<'a>{
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {
fn accept(&mut self, inp: &'a u8) { self.myref = Some(inp); }
}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl{myref: None})
}
fn user<'a>(obj: &mut Trait<'a>) {}
fn parent<'a>(x: &'a u8) {
let mut pool = new();
user(pool.borrow_mut());
}
The compiler error is
error: `pool` does not live long enough
--> src/wtf.rs:22:10
|
22 | user(pool.borrow_mut());
| ^^^^ does not live long enough
23 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
Which makes absolutely no sense. How is the borrower outliving anything? I'm not even using the borrowed value!
Ok, this does make sense, but it's hard to see due to lifetime elision. So, here's your code with all the lifetimes written out explicitly, and with irrelevant details culled:
use std::borrow::BorrowMut;
trait Trait<'a> {}
struct Impl<'a> {
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl { myref: None })
}
fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'b)) {}
fn parent() {
/* 'i: */ let mut pool/*: Box<Trait<'x> + 'x>*/ = new();
/* 'j: */ let pool_ref/*: &'i mut Box<Trait<'x> + 'x>*/ = &mut pool;
/* BorrowMut<T>::borrow_mut<'d>(&'d mut Self) -> &'d mut T */
/* 'k: */ let pool_borrow/*: &'i mut (Trait<'x> + 'x)*/ = Box::borrow_mut(pool_ref);
user(pool_borrow);
}
Now, from the perspective of the last line of parent, we can work out the following equivalences by just reading the definition of user and substituting the lifetimes we have in parent:
'a = 'x
'b = 'i
'b = 'x
Furthermore, this lets us conclude that:
'x = 'i
This is the problem. Because of the way you've defined user, you've put yourself in a situation where the lifetime of the pool_ref borrow (which is equal to the lifetime of the pool storage location you're borrowing from) must be the same as the lifetime 'x being used in the thing being stored in pool.
It's a bit like the Box being able to have a pointer to itself before it exists, which doesn't make any sense.
Either way, the fix is simple. Change user to actually have the correct type:
fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'a)) {}
This matches the type produced by new. Alternately, just don't use borrow_mut:
user(&mut *pool)
This works because it is "re-borrowing". Calling borrow_mut translates the lifetimes more or less directly, but re-borrowing allows the compiler to narrow the borrows to shorter lifetimes. To put it another way, explicitly calling borrow_mut doesn't allow the compiler enough freedom to "fudge" the lifetimes to make them all line up, re-borrowing does.
As a quick aside:
I'm not even using the borrowed value!
Irrelevant. Rust does type- and lifetime-checking entirely locally. It never looks at the body of another function to see what it's doing; it goes on the interface alone. The compiler neither checks, nor cares, what you're doing inside a different function.
Note that there's more to the error message:
error: `pool` does not live long enough
--> src/main.rs:25:10
|>
25 |> user(pool.borrow_mut());
|> ^^^^
note: reference must be valid for the block at 23:25...
--> src/main.rs:23:26
|>
23 |> fn parent<'a>(x: &'a u8) {
|> ^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 24:25
--> src/main.rs:24:26
|>
24 |> let mut pool = new();
|> ^
Let's look at user:
fn user<'a>(obj: &mut Trait<'a>) {}
This says that it will accept a mutable reference (with an unnamed lifetime) to a trait object parameterized with the lifetime 'a.
Turning to new, I'd say the method is highly suspicious:
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl { myref: None })
}
This says that it will return a boxed trait object with whatever lifetime the caller specifies. That basically never makes sense.
All that said, I'm not clear why the code chooses to use borrow_mut. I would have written that more directly:
user(&mut *pool);
This dereferences the Box<Trait> to get a Trait, then takes a mutable reference, yielding &mut Trait, which compiles.
I cannot currently explain why BorrowMut differs in behavior.
I'm not sure why this error happens, but I can give solutions!
First, it seems that using borrow_mut unnecessarily restricts the lifetime of the returned reference. Using operators to create the reference solves the error.
fn parent() {
let mut pool = new();
user(&mut *pool);
}
However, if we don't do that, we can solve the error by adding a lifetime bound to the Trait object in user's obj argument.
fn user<'a>(obj: &mut (Trait<'a> + 'a)) {}

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