Using FnMut() closures in a static function - rust

Background: I'm trying to avoid the use of Mutex/RefCell/Option dance in an interrupt handler for an embedded system. I do not want to use the heap (and I don't think it should be necessary -- but feel free to show me wrong). I can't use std. I've looked at cortex-m-rtfm and it's neat, but pretty invasive. And anyway, this is a bit of a learning exercise. If it works out, I would prefer to use closures to handle interrupts since it feels closer to bare Rust. I am a total Rust newbie -- I've been working with it for about a week. I have tried a lot of different variants of this as I've read through documentation, re-read the Rust book, blog posts, etc.,. I cannot figure what I'm doing wrong here.
Here's the sample code. Questions to follow:
use core::cell::UnsafeCell;
pub struct Handler<'a> {
h: UnsafeCell<&'a dyn FnMut()>,
}
impl<'a> Handler<'a> {
pub fn new<T: FnMut()>(closure: &'a dyn FnMut()) -> Self {
Handler {
h: UnsafeCell::new(closure),
}
}
pub fn call(&self) {
unsafe {
// NOTE: type returned by `self.h.get()` is
// `*mut &'a (dyn std::ops::FnMut() + 'a)`
let h: *mut FnMut() = self.h.get();
h();
}
}
}
unsafe impl<'a> Sync for Handler<'a> {}
fn default_handler() {}
static HANDLER: Handler = Handler {
h: UnsafeCell::new(&default_handler),
};
#[test]
fn call_handler() {
let mut a: u32 = 0;
let foo = move || a += 1;
let mut handler = Handler::new(&foo);
handler.call();
a += 2; // Shouldn't this cause compilation failure because `a`
// was moved into the closure above?
assert_eq!(a, 1);
}
Error
error[E0618]: expected function, found `*mut dyn std::ops::FnMut()`
--> src/lib.rs:19:13
|
18 | let h: *mut FnMut() = self.h.get();
| - `*mut dyn std::ops::FnMut()` defined here
19 | h();
| ^--
| |
| call expression requires function
error[E0277]: expected a `std::ops::Fn<()>` closure, found `(dyn std::ops::FnMut() + 'a)`
--> src/lib.rs:18:35
|
18 | let h: *mut FnMut() = self.h.get();
| ^^^^^^^^^^^^ expected an `Fn<()>` closure, found `(dyn std::ops::FnMut() + 'a)`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `(dyn std::ops::FnMut() + 'a)`
= note: wrap the `(dyn std::ops::FnMut() + 'a)` in a closure with no arguments: `|| { /* code */ }
= note: required because of the requirements on the impl of `std::ops::FnMut<()>` for `&'a (dyn std::ops::FnMut() + 'a)`
= note: required for the cast to the object type `dyn std::ops::FnMut()`
Explanation: Hopefully, my intentions are obvious: I'll set up the closure for HANDLER in main, before going into a busy-loop that never exits. The closure will mutably borrow the stuff the interrupt handler needs for its operation, preventing its use in other contexts. Since main never exits, stack-allocated variables within it are effectively 'static, so there shouldn't be a problem with referencing them at any point after the closure is set. The interrupt handler itself (not shown) will simply call the closure to do its work. To work around the storage of a closure (which is not Sized) in a static, I need to store a reference to the closure. UnsafeCell isn't necessarily required, but since I'm using FnMut() its referents need to be mutable, which runs into statics require immutable values when trying to set up default_handler during the creation of a static mut HANDLER.
Questions:
As posted, this code doesn't compile. For some reason, the
assignment let h: *mut FnMut() = self.h.get() tells me that it
expected an Fn<()> closure, found (dyn std::ops::FnMut() + 'a). Well, I know why it found that type. But why is it expecting Fn<()>?
In the call_handler test, why is this compiling at all? The foo closure moves its captured variable a. How is it possible to mutate it after the closure definition? When I've tried this code with a type that doesn't implement Copy, it fails as expected, but I'm frankly surprised that trait matters. Isn't the point that foo owns a now?
I realize there are potential issues with changing HANDLER.h at arbitrary points in the code, but I will worry about solving those later, after there's a viable proof-of-concept.

I have found a way to do what I want. It is grossly unsafe for general use, and appropriate mechanisms to hide its lack of safety have to be investigated, and may not even be possible. The main trick is to convert the mutable trait object into a dynamic one using an as cast, and using core::mem::transmute to change its lifetime to static. Here's the code:
use core::cell::UnsafeCell;
use core::mem::transmute;
struct Handler {
h: UnsafeCell<*const dyn FnMut()>,
}
impl Handler {
unsafe fn replace(&self, f: &dyn FnMut()) {
let f_static: &'static dyn FnMut() = transmute(f);
*self.h.get() = f_static;
}
unsafe fn call(&self) {
let f: &mut dyn FnMut() = &mut *(*self.h.get() as *mut dyn FnMut());
f();
}
}
unsafe impl Sync for Handler {}
fn default_handler() {}
static HANDLER: Handler = Handler {
h: UnsafeCell::new(&default_handler),
};
fn main() {
let mut x: u32 = 0;
let closure = || x += 2;
unsafe {
HANDLER.replace(&closure);
HANDLER.call();
};
println!("x: {}", x); // Prints 2
}
The closure wrapped by Handler.h is inside an UnsafeCell to facilitate its replacement at runtime (inside, and only inside, the main loop).

Related

"temporary value dropped while borrowed" with capturing closure

Please consider the following example (playground):
struct Animal<'a> {
format: &'a dyn Fn() -> (),
}
impl <'a>Animal<'a> {
pub fn set_formatter(&mut self, _fmt: &'a dyn Fn() -> ()) -> () {} // Getting rid of 'a here satisfies the compiler
pub fn bark(&self) {}
}
fn main() {
let mut dog: Animal = Animal { format: &|| {()} };
let x = 0;
dog.set_formatter(&|| {
println!("{}", x); // Commenting this out gets rid of the error. Why?
});
dog.bark(); // Commenting this out gets rid of the error. Why?
}
This gives the following compilation error:
Compiling playground v0.0.1 (/playground)
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:13:24
|
13 | dog.set_formatter(&|| {
| ________________________^
14 | | println!("{}", x); // Commenting this out gets rid of the error. Why?
15 | | });
| | ^ - temporary value is freed at the end of this statement
| |_____|
| creates a temporary which is freed while still in use
16 | dog.bark(); // Commenting this out gets rid of the error. Why?
| --- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error: aborting due to previous error
For more information about this error, try `rustc --explain E0716`.
error: could not compile `playground`
To learn more, run the command again with --verbose.
This kind of makes sense as the closure that I'm passing to dog.set_formatter(...) is indeed a temporary which (I guess) is freed when execution proceeds to dog.bark();.
I know that getting rid of the explicit lifetime annotation in the implementation of set_formatter seems to satisfy the compiler (note the missing 'a before dyn):
pub fn set_formatter(&mut self, _fmt: & dyn Fn() -> ()) -> () {}
However, I don't understand the following:
Why does the problem go away when I comment out println!("{}", x); inside the closure? I'm still passing a temporary which I expect the compiler to complain about, but it doesn't.
Why does the problem go away when I comment out dog.bark(); at the end? Again, I'm still passing a temporary closure which is freed but now the compiler is happy. Why?
The first thing to understand is that &|| () has a 'static lifetime:
fn main() {
let closure: &'static dyn Fn() = &|| (); // compiles
}
Another thing worth mentioning is that a closure's lifetime cannot exceed the lifetime of any of the variables it captures from its environment, which is why if we try to pass a non-static variable to our static closure it would fail to compile:
fn main() {
let x = 0; // non-static temporary variable
let closure: &'static dyn Fn() = &|| {
println!("{}", x); // x reference captured by closure
}; // error: trying to capture non-static variable in static closure
}
We'll come back to that. Anyway, so if I have a struct which is generic over references, and I pass it a 'static reference, I'll have a 'static instance of that struct:
struct Dog<'a> {
format: &'a dyn Fn(),
}
fn main() {
let dog: Dog<'static> = Dog { format: &|| () }; // compiles
}
The second thing to understand is once you instantiate a type you cannot change it. This includes any of its generic parameters, including lifetimes. Once you have a Dog<'static> it will always be a Dog<'static>, you cannot convert it into a Dog<'1> for some anonymous lifetime '1 that is shorter than 'static.
This has some strong implications, one of which is that your set_formatter method probably doesn't behave how you think it behaves. Once you have a Dog<'static> you can only pass 'static formatters to set_formatter. The method looks like this:
impl<'a> Dog<'a> {
fn set_formatter(&mut self, _fmt: &'a dyn Fn()) {}
}
But since we know we're working with a Dog<'static> we can substitute out the generic lifetime parameter 'a with 'static to see what we're really working with:
// what the impl would be for Dog<'static>
impl Dog {
fn set_formatter(&mut self, _fmt: &'static dyn Fn()) {}
}
So now that we've gotten all of that context out of the way let's get to your actual questions.
Why does the problem go away when I comment out println!("{}", x); inside the closure? I'm still passing a temporary which I expect the compiler to complain about, but it doesn't.
Why it fails, with comments:
struct Dog<'a> {
format: &'a dyn Fn(),
}
impl<'a> Dog<'a> {
fn set_formatter(&mut self, _fmt: &'a dyn Fn()) {}
}
fn main() {
let mut dog: Dog<'static> = Dog { format: &|| () };
// x is a temporary value on the stack with a non-'static lifetime
let x = 0;
// this closure captures x by reference which ALSO gives it a non-'static lifetime
// and you CANNOT pass a non-'static closure to a Dog<'static>
dog.set_formatter(&|| {
println!("{}", x);
});
}
The reason this error is "fixed" by commenting out the line println!("{}", x); is because it gives the closure a 'static lifetime again since it no longer borrows the non-'static variable x.
Why does the problem go away when I comment out dog.bark(); at the end? Again, I'm still passing a temporary closure which is freed but now the compiler is happy. Why?
This weird edge case only seems to happen when we don't explicitly type-annotate the dog variable with Dog<'static>. When a variable doesn't have an explicit type annotation the compiler attempts to infer its type, but it does so lazily, and tries to be as flexible as possible, giving the benefit of the doubt to the programmer, in order to make the code compile. It really should throw a compile error even without the dog.bark() but it doesn't for whatever mysterious reasons. The point is it's not the dog.bark() line that is making the code fail to compile, it should be failing to compile at the set_formatter line regardless, but for whatever reason the compiler doesn't bother to throw an error until you try to use dog again after that offending line. Even just dropping dog will trigger the error:
struct Dog<'a> {
format: &'a dyn Fn(),
}
impl<'a> Dog<'a> {
fn set_formatter(&mut self, _fmt: &'a dyn Fn()) {}
}
fn main() {
let mut dog = Dog { format: &|| () };
let x = 0;
dog.set_formatter(&|| {
println!("{}", x);
});
drop(dog); // triggers "temp freed" error above
}
And since we've come this far, let's answer your unofficial third question, paraphrased by me:
Why does getting rid of the 'a in the set_formatter method satisfy the compiler?
Because it changes what is effectively this for Dog<'static>:
// what the impl would be for Dog<'static>
impl Dog {
fn set_formatter(&mut self, _fmt: &'static dyn Fn()) {}
}
Into this:
// what the impl would now be for Dog<'static>
impl Dog {
fn set_formatter(&mut self, _fmt: &dyn Fn()) {}
}
So now you can pass non-'static closures to a Dog<'static> although it's pointless since the method doesn't actually do anything, and the compiler will complain again the moment you actually try to set the closure in the Dog<'static> struct.

Why do Rust lifetimes matter when I move values into a spawned Tokio task?

I'm trying to create a struct that will manage a Tokio task with one tokio::sync::mpsc::Sender that sends input to the task, one tokio::sync::mpsc::Receiver that receives output from the task, and a handle that I can join at the end.
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
// A type that implements BlockFunctionality consumes instances of T and
// produces either Ok(Some(U)) if an output is ready, Ok(None) if an output
// is not ready, or an Err(_) if the operation fails
pub trait BlockFunctionality<T, U> {
fn apply(&mut self, input: T) -> Result<Option<U>, &'static str>;
}
pub struct Block<T, U> {
pub tx_input: mpsc::Sender<T>,
pub rx_output: mpsc::Receiver<U>,
pub handle: JoinHandle<Result<(), &'static str>>,
}
impl<T: Send, U: Send> Block<T, U> {
pub fn from<B: BlockFunctionality<T, U> + Send>(b: B) -> Self {
let (tx_input, mut rx_input) = mpsc::channel(10);
let (mut tx_output, rx_output) = mpsc::channel(10);
let handle: JoinHandle<Result<(), &'static str>> = tokio::spawn(async move {
let mut owned_b = b;
while let Some(t) = rx_input.recv().await {
match owned_b.apply(t)? {
Some(u) => tx_output
.send(u)
.await
.map_err(|_| "Unable to send output")?,
None => (),
}
}
Ok(())
});
Block {
tx_input,
rx_output,
handle,
}
}
}
When I try to compile this, I get this error for B and a similar one for the other two type parameters:
|
22 | pub fn from<B: BlockFunctionality<T, U> + Send>(b:B) -> Self {
| -- help: consider adding an explicit lifetime bound...: `B: 'static +`
...
27 | let handle:JoinHandle<Result<(), &'static str>> = tokio::spawn(async move {
| ^^^^^^^^^^^^ ...so that the type `impl std::future::Future` will meet its required lifetime bounds
I'm having a hard time understanding where the problem is with lifetimes. The way I understand it, lifetime problems usually come from references that don't live long enough, but I'm moving values, not using references. I move b, rx_input, and tx_output into the closure and I keep tx_input, rx_output, and handle in the calling scope. Does anyone know how to satisfy the compiler in this case?
Those values may be references or contain references. Reference types are valid types: B could be &'a str. Or B could be SomeType<'a>, a type with a lifetime parameter, that itself contains a &'a str.
To say that B: 'static means that all lifetime parameters of B outlive 'static (ref). For example, types which own their own data and thus have no lifetime parameters (e.g. String) satisfy this bound. But &'static str also satisfies the bound.
Because tokio::spawn creates something whose lifetime is not statically scoped, it requires a 'static argument.
So to satisfy the compiler, add the 'static bounds:
impl<T: 'static + Send, U: 'static + Send> Block<T, U> {
pub fn from<B: 'static + BlockFunctionality<T, U> + Send>(b:B) -> Self {

the trait `std::ops::Fn<()>` is not implemented for [closure ...] but only with a binding from the outer scope

fn main() {
let s = Some("xyz".to_string()); //compiler error
let foo = Box::new(|| s) as Box<Fn() -> Option<String>>; //ok
let bar = Box::new(|| Some("xyz".to_string())) as Box<Fn() -> Option<String>>;
println!("{:?}", foo());
println!("{:?}", bar());
}
gives the error
error[E0277]: the trait bound `[closure#src/main.rs:5:24: 5:28 s:std::option::Option<std::string::String>]: std::ops::Fn<()>` is not satisfied
--> src/main.rs:5:15
|
5 | let foo = Box::new(|| s) as Box<Fn() -> Option<String>>;
| ^^^^^^^^^^^^^^ the trait `std::ops::Fn<()>` is not implemented for `[closure#src/main.rs:5:24: 5:28 s:std::option::Option<std::string::String>]`
|
= note: required for the cast to the object type `std::ops::Fn() -> std::option::Option<std::string::String>`
error: aborting due to previous error
The docs for Trait std::ops::Fn state:
Fn is implemented automatically by closures which only take immutable references to captured variables or don't capture anything at all,
s isn't mutable, but it's not a reference and I'm moving it.
If I call s.clone() the compiler error goes away, but in my real case I want to avoid that.
Same error if I use FnMut FnOnce complains about not knowing the size, even though it is Boxed.
Is there a way I can make this work with moved data?
playground
If this was allowed, what would happen the second time the closure was called? Remember, the first time the closure is called, it moves s, so s now has no valid value.
There are a few ways to make this work, depending on what you need exactly.
Make the closure return a reference to the string instead.
Note: We need to write out 'a explicitly on the right-hand side of the as cast expression, otherwise the compiler gives an error. I don't think we can write a correct lifetime without introducing an intermediate function (make_foo here).
fn make_foo<'a>(s: &'a Option<String>) -> Box<Fn() -> Option<&'a str> + 'a> {
Box::new(move || s.as_ref().map(|s| &**s)) as Box<Fn() -> Option<&'a str> + 'a>
}
fn main() {
let s = Some("xyz".to_string());
let foo = make_foo(&s);
println!("{:?}", foo());
}
Use FnOnce FnBox instead of Fn. FnOnce closures can move, but can be called at most once. Since we can't call a Box<FnOnce()> as of Rust 1.23.0, we need to use Box<FnBox()>.
#![feature(fnbox)]
use std::boxed::FnBox;
fn main() {
let s = Some("xyz".to_string());
let foo = Box::new(|| s) as Box<FnBox() -> Option<String>>;
println!("{:?}", foo());
}
However, since FnBox is unstable, you can only use it with a nightly compiler. If you want to support stable compilers, you can use the BoxFnOnce type defined in the boxfnonce crate instead (though you need to explicitly call the closure as x.call(); x() won't work).

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