Consider next code:
fn get_ref<'a, R>(slice: &'a Vec<i32>, f: fn(&'a Vec<i32>) -> R) -> R
where
R: 'a,
{
f(slice)
}
fn main() {
let v = [1,2,3,4,5,6];
let iter = get_ref(&v, |x| x.iter().skip(1).take(2));
println!("{:?}", iter.collect::<Vec<_>>());
}
I create some static variable, then apply some function to its reference and get a result.
It seems to work totally fine. At least it successfully compiles.
Now I am trying to add next level of abstraction. And things are getting weird...
fn owned<'a, R>(owner: Vec<i32>, f: fn(&'a Vec<i32>) -> R)
where
R: 'a,
{
let _ = get_ref(&owner, f); // error occurs here
// `owner` does not live long enough.
}
// get_ref is the same as in the first example
fn get_ref<'a, R>(slice: &'a Vec<i32>, f: fn(&'a Vec<i32>) -> R) -> R
where
R: 'a,
{
f(slice)
}
fn main() {
let v = [1,2,3,4,5,6];
owned(v, |x| x.iter().skip(1).take(2));
}
For me it looks like pretty the same code. But Rust fails to compile it. I really don't understand why this is happening and how should I rewrite my code to compile.
Imagine if I decide to call the function owned<'static, i32>(Vec<i32>, foo) with foo defined as:
fn foo(vec: &'static Vec<i32>) -> i32 { ... }
This satisfies the bounds for owned, since i32: 'static. However this means that you must have a static reference to call f, but owner does not live forever, since it is destroyed at the end of owned.
One way to fix it is to use the following:
fn owned<R>(owner: Vec<i32>, f: for<'a> fn(&'a Vec<i32>) -> R) {
let _ = get_ref(&owner, f);
}
It says that f must be callable with any lifetime, rather than just some specific lifetime. However, this has the consequence that R cannot borrow from the argument, since R is declared in a larger scope than 'a. There isn't any way to fix that while keeping the generics as is.
This answer was taken from my response to this thread on URLO.
Related
I'm having difficulties understanding lifetime parameters in the following code snippet.
struct C {
data: Vec<u32>,
cols: usize
}
trait M<'s> {
fn get(&'s self, r: usize, c: usize) -> u32;
fn get_mut(&'s mut self, r: usize, c: usize) -> &'s mut u32;
}
impl<'s> M<'s> for C {
fn get(&'s self, r: usize, c: usize) -> u32 {
return self.data[self.cols*r+c];
}
fn get_mut(&'s mut self, r: usize, c: usize) -> &'s mut u32 {
return &mut self.data[self.cols*r+c];
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create() -> C {
let data = vec![0u32,1u32,2u32,3u32,4u32,5u32];
return C{data, cols: 3};
}
fn select<'s, 'r: 's>(data: &'r mut dyn M<'s>) {
let mut _val: u32 = 0;
for r in 0..2 {
for c in 0..3 {
_val += *data.get_mut(r,c);
}
}
}
#[test]
fn test_select() {
let mut data = create();
select(&mut data);
}
}
The code snippet does not compile, because it complains that *data is borrowed multiple times in the function fn select<'s, 'r: 's>(data: &'r mut dyn M<'s>) {} when calling get_mut (once in every loop iteration). Even safeguarding the questionable line with curly braces (and thus creating a new context) does not help. My expectation (in both cases) would be, that the mutable borrow of &mut data should end right after the execution of that line.
On the other hand, when I remove all lifetime parameters, everything works as expected.
Can anyone explain what's the difference between the two versions (with and without explicit lifetimes)?
I've also tried to find information about additional lifetime parameters for traits, in particular specifying their meaning, but I have found none. So I assume, that they are just a declaration of the used labels inside the trait. But if that is so, then I would assume that leaving out the lifetime parameters completely and applying the eliding rules would lead to the same result.
There are two things to consider. The first is when you use a generic lifetime for a function, that lifetime must be larger than the life of the function call simply by construction. And the second is since the lifetime self is tied to the lifetime parameter of the trait, when you call .get_mut(), data is borrowed for the lifetime of 's. Combining those two principles, data is borrowed for longer than the function call so you can't call it again (its already mutably borrowed).
On the other hand, when I remove all lifetime parameters, everything works as expected. Can anyone explain what's the difference between the two versions (with and without explicit lifetimes)?
Without a generic lifetime on M, the methods will behave as if defined as so:
impl M for C {
fn get<'a>(&'a self, r: usize, c: usize) -> u32 {
return self.data[self.cols * r + c];
}
fn get_mut<'a>(&'a mut self, r: usize, c: usize) -> &'a mut u32 {
return &mut self.data[self.cols * r + c];
}
}
Thus there is no lifetime associated with the trait; the lifetimes given and returned from the function are generic only to those method calls. And since the compiler can choose a new lifetime 'a for each call and it will always pick the shorted lifetime to satisfy its usage, you can then call data.get_mut() multiple times without worry. And I'll be honest, having the lifetime on the trait didn't make much sense with the original code; as mentioned, the code works with all lifetime annotations removed: playground.
Why does this compile:
fn func<T>(
callback: impl FnOnce(&mut i64) -> T,
) -> T {
let v = 42;
callback(&mut 42)
}
but this not?:
fn func<'a, T>(
callback: impl FnOnce(&'a mut i64) -> T,
) -> T {
let v = 42;
callback(&mut 42)
}
Even this doesn't compile:
fn func<'a, T: 'static>(
callback: impl FnOnce(&'a mut i64) -> T,
) -> T {
let v = 42;
callback(&mut 42)
}
Is there a way to tell Rust that the T returned from the callback doesn't hold any references to 'a? I thought : 'static would forbid references in general but it doesn't seem to work. Unfortunately, I do need to give 'a a name because I'm using the lifetime elsewhere, the actual code is somewhat more complicated than this minimal example.
In your first snippet, the lifetimes are elided via Higher-Ranked Trait Bounds:
fn func<T>(
callback: impl for<'a> FnOnce(&'a mut i64) -> T,
) -> T {
let v = 42;
callback(&mut 42)
}
That means the closure can be called with any lifetime, and that includes the lifetime of v.
In your second snippet, the lifetime is chosen by the caller. This is not related to T: for example, the caller can choose 'static, then store the parameter in a static. There is just no way to satisfy this requirement with a variable defined in the function.
Let's say I have this code (it's contrived, since it's heavily simplified):
enum Foo<'a, T> where T: 'a {
Bar(&'a mut Vec<T>),
}
fn main() {
let mut v = vec![1, 2];
let foo: Foo<isize> = Foo::Bar(&mut v);
let a = match foo {
Foo::Bar(ref mut v) => &mut v[..],
};
a[1] = 10;
println!("a = {:?}", a);
}
This works and everyone is happy. However, if I try to clean it up a bit by placing the match statement inside a function, I can't even get the function to compile, let alone put it to work for me. One of my many attempts looks like this:
fn unpack<'a, T>(foo: Foo<'a, T>) -> &'a mut [T] {
match foo {
Foo::Bar(ref mut v) => &mut v[..],
}
}
I just get the error:
error: `foo.0` does not live long enough
I have been trying to change to multiple lifetimes and adding a where clause (just like I had to do to get the Enum to work), but I can't seem to get it to work. My question is simply if it works (and how) or if the only option here is to use a macro.
Foo::Bar(ref mut v) borrows &mut Vec<T> from foo so it can't outlive foo (which only lives until the end of the function). What you actually want to do is take it (by value) so you should match on Foo::Bar(v):
fn unpack<'a, T>(foo: Foo<'a, T>) -> &'a mut [T] {
match foo {
Foo::Bar(v) => &mut v[..],
}
}
Note: Rust will deref v as needed so the following will also work:
fn unpack<'a, T>(foo: Foo<'a, T>) -> &'a mut [T] {
match foo {
Foo::Bar(v) => v,
}
}
I have two types: Lexer and SFunction.
SFunction stands for stateful function and is definined like so:
struct SFunction {
f: Option<Box<FnMut() -> SFunction>>,
}
The important part is that any SFunction references a closure that returns an SFunction.
Now I want to have these functions carry state by each affecting the same Lexer. This means that each of these SFunctions has to have a lifetime that depends on a specific Lexer.
Here's some more code if you want to get more of a sense of what I'm doing with this:
impl Lexer {
fn lex(&mut self) {
self.sfunction(Lexer::lexNormal).call()
}
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(|| f(self)))
// SFunction { f: Some(Box::new(move ||f(self))) }
}
fn lexNormal(&mut self) -> SFunction {
return SFunction::empty()
}
}
(Here’s a full version of the code in the Rust playground.)
How do I specify this lifetime requirement in the code?
The compiler errors I'm getting say "cannot infer an appropriate lifetime for capture of self by closure due to conflicting requirements". I'm pretty sure the "conflicting requirements" here is that a Box type assumes the lifetime to be 'static. I could do something like Box<FnMut() -> SFunction + 'a> where 'a is a lifetime defined by the Lexer it depends upon, but I'm not sure how to define such an 'a.
Thanks for your help!
The problem is in this line:
SFunction::new(Box::new(|| f(self)))
Here, self is a reference to a Lexer, but there's no guarantee that the lexer will live long enough. In fact, it needs to live for the 'static lifetime! Without a lifetime specified, a boxed trait object will use the 'static lifetime. Said in code, these two declarations are equivalent:
<Box<FnMut() -> SFunction>>
<Box<FnMut() -> SFunction> + 'static>
And you can make your code compile (in an unsatisfactory way) by restricting it to accept only references that will live for the 'static lifetime:
fn lex(&'static mut self) {
self.sfunction(Lexer::lex_normal).call()
}
fn sfunction(&'static mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || f(self)))
}
Of course, it's very doubtful that you will have a Lexer with the static lifetime, as that would mean that it's lexing static data, which wouldn't be very useful. That means we need to include lifetimes in your trait object... as you suggested.
Ultimately what helped to see the problem was to restructure your closure a bit:
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || {
// f(self)
let s2 = self;
let f2 = f;
f2(s2)
}))
}
Compiling this produces an error that points to what seems to be the real problem:
<anon>:31:22: 31:26 error: cannot move out of captured outer variable in an `FnMut` closure [E0507]
<anon>:31 let s2 = self;
^~~~
<anon>:31:17: 31:19 note: attempting to move value to here
<anon>:31 let s2 = self;
^~
<anon>:31:17: 31:19 help: to prevent the move, use `ref s2` or `ref mut s2` to capture value by reference
I believe this is because a FnMut closure may be called multiple times, which would mean that the reference enclosed in the closure would need to be copied around, which would be bad news as &mut references should be unique.
All together, this code works:
struct SFunction<'a> {
f: Option<Box<FnOnce() -> SFunction<'a> + 'a>>,
}
impl<'a> SFunction<'a> {
fn new(f: Box<FnOnce() -> SFunction<'a> + 'a>) -> SFunction<'a> {
SFunction {
f: Some(f),
}
}
fn empty() -> SFunction<'a> {
SFunction {
f: None,
}
}
fn call(self) { }
}
struct Lexer;
impl Lexer {
fn lex(&mut self) {
self.sfunction(Lexer::lex_normal).call()
}
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || f(self)))
}
fn lex_normal<'z>(&'z mut self) -> SFunction<'z> {
SFunction::empty()
}
}
fn main() {
let mut l = Lexer;
l.lex()
}
I hope my explanation is right and that the changed code still suits your use case!
Can somebody help me to rewrite this piece of code with new unboxed closures:
struct Builder;
pub fn build(rules: |params: &mut Builder|) -> Builder {
let mut builder = Builder::new();
rules(&mut builder);
builder
}
I tried to write like this, but I got a lifetime error:
pub fn build<F>(rules: F) -> Builder where F: FnOnce<(&mut Builder,), ()> {
let mut builder = Builder::new();
rules(&mut builder);
builder
}
valico/src/builder.rs:48:59: 48:71 error: missing lifetime specifier [E0106]
valico/src/builder.rs:48 pub fn build<F>(rules: F) -> Builder where F: FnOnce<(&mut Builder,), ()> {
^~~~~~~~~~~~
What lifetime I need to specify? Simplified example in the sandbox.
This requires higher rank trait bounds, specifically, higher rank lifetimes. The full unsugared syntax would be F: for<'a> FnOnce<(&'a mut Builder,), ()>.
Using a lifetime on the function can't work, e.g. if we had
pub fn build<'b, F>(rules: F) -> Builder where F: FnOnce<(&'b mut Builder,), ()>
This says that build works with whatever lifetime the caller wishes (e.g. they could chose 'b == 'static), but this is invalid, because there is a specific concrete lifetime that needs to be the used: the lifetime of the &mut builder inside the function. Using F: for<'a> ... in a bound says that F works with any lifetime 'a, so the compiler sees that it is legal to substitute in the one of &mut builder.
As I hinted above, that's the really ugly unsugared syntax. There's two successive ways this can be made much nicer. Firstly, the canonical way to use the closure traits is the () sugar: for<'a> FnOnce(&'a mut Builder) -> (), or, like with the rest of Rust, the -> () can be dropped: for<'a> FnOnce(&'a mut Builder). (NB. this is just sugar for FnOnce<...>, but only the sugared syntax will be stabilised for interacting with these traits at 1.0.)
Then, the paren syntax has a little extra rule: it automatically inserts lifetimes that act like for<'a> (specifically, it undergoes lifetime elision with any inserted lifetime placed into a for on the trait), so just F: FnOnce(&mut Builder) is equivalent to F: for<'a> FnOnce(&'a mut Builder), and it's the recommended version.
Applying these fixes to your playpen example:
pub fn initialize_with_closure<F>(rules: F) -> uint where F: FnOnce(&mut uint) {
let mut i = 0;
rules(&mut i);
i
}
// equivalently
pub fn initialize_with_closure_explicit<F>(rules: F) -> uint where F: for<'a> FnOnce(&'a mut uint) -> () {
let mut i = 0;
rules(&mut i);
i
}
pub fn main() {
initialize_with_closure(|i: &mut uint| *i = *i + 20);
initialize_with_closure_explicit(|i: &mut uint| *i = *i + 20);
}
playpen