I want to write a closure that takes an object and returns an iterator from it. The idea is to store the closure in a structure and apply as needed:
fn main() {
let iter_wrap = |x: &String| Box::new(x.chars());
let test = String::from("test");
for x in iter_wrap(&test) {
println!("{}", x);
}
}
This causes the error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:2:45
|
2 | let iter_wrap = |x: &String| Box::new(x.chars());
| ^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 2:21...
--> src/main.rs:2:21
|
2 | let iter_wrap = |x: &String| Box::new(x.chars());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:2:43
|
2 | let iter_wrap = |x: &String| Box::new(x.chars());
| ^
note: but, the lifetime must be valid for the call at 5:14...
--> src/main.rs:5:14
|
5 | for x in iter_wrap(&test) {
| ^^^^^^^^^^^^^^^^
note: ...so that argument is valid for the call
--> src/main.rs:5:14
|
5 | for x in iter_wrap(&test) {
| ^^^^^^^^^^^^^^^^
I tried to change String to Vec and remove boxing, but the result is the same.
How can I make it compile?
Closures with borrows in parameter or return types have some known bugs as shown in this issue report and the others it links to: https://github.com/rust-lang/rust/issues/58052
There are a few ways to work around the issue.
Using fully qualified syntax
fn main() {
let iter_wrap = |x| Box::new(str::chars(x));
let test = String::from("test");
for x in iter_wrap(&test) {
println!("{}", x);
}
}
Using a type annotation in the closure body
fn main() {
let iter_wrap = |x| {let x: &String = x; Box::new(x.chars()) };
let test = String::from("test");
for x in iter_wrap(&test) {
println!("{}", x);
}
}
I'm not entirely sure what you try to achieve there, but basically just looking at your provided example, you don't need a closure, but a function:
use std::str::Chars;
fn main() {
fn iter_wrap(s: &str) -> Chars {
s.chars()
}
let test = "test".to_string();
for c in iter_wrap(&test) {
println!("{}", c);
}
}
Or you could have a closure, that is enclosing the outside world, in this case, your string:
fn main() {
let test = "test".to_string();
let iter_wrap = || test.chars();
for c in iter_wrap() {
println!("{}", c);
}
}
You need to define and use a lifetime that is shorter than the lifetime of the function itself. I tried this and it worked:
fn foo<'a, 'b: 'a>() {
let test = String::from("test");
let iw = |x: &'b String| {
x.chars()
};
for x in iw(&test) {
println!("{}", x);
}
}
fn main() {
foo()
}
Just using lifetime 'a is not sufficient, you need a lifetime that is shorter than that, so 'b: 'a.
Now what I cannot explain is that, with both 'a and 'b defined, using &'a String in the closure definition works as well ...
Related
Here is trivial reproduction (nightly rustc as of 2-feb-23):
fn main() {
let closure = |_v| {};
// this one works fine
// let closure = |_v: &_| {};
{
let x = 1;
closure(&x);
}
{
let y = 1;
closure(&y);
}
}
The error is:
6 | let x = 1;
| - binding `x` declared here
7 | closure(&x);
| ^^ borrowed value does not live long enough
8 | }
| - `x` dropped here while still borrowed
...
11 | closure(&y);
| ------- borrow later used here
Which doesn't make sense, as variable x is not captured by the closure, but is just an argument passed by reference.
Providing an explicit reference for the closure parameter _v: &_ solves the issue, but shouldn't it be inferred automatically?
Is it some bug/limitation of the borrow checker? Or I'm missing something more fundamental here?
This looks like it could be a bug with type inference to me.
I think what is happening is
fn main() {
let closure = |_v| {};
{
let x = 1; // Lifetime `a begins
closure(&x); // closure is inferred to be fn(&'a i32)
// Lifetime 'a end
}
{
let y = 1; // Lifetime `b begins
closure(&y); // attempt to call closure fn(&'a i32) with &'b i32
// Lifetime 'b end
}
}
but defining the closure as
let closure = |_v: &'_ i32| {};
Stops the compiling from inferring its lifetime and uses hrtb as it should.
This code works fine (Playground):
struct F<'a> {
x: &'a i32,
}
impl<'a> F<'a> {
fn get<'b>(&'b self) -> &'a i32 {
self.x
}
}
fn main() {
let x = 3;
let y = F { x: &x };
let z = y.get();
}
But when I change x to be a mutable reference instead (Playground):
struct Foo<'a> {
x: &'a mut i32, // <-- `mut` added
}
impl<'a> Foo<'a> {
fn get(&self) -> &'a i32 {
self.x
}
}
fn main() {
let mut x = 3; // <-- `mut` added
let y = Foo { x: &mut x }; // <-- `mut` added
let z = y.get();
}
I get this error:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/main.rs:7:9
|
7 | self.x
| ^^^^^^
|
note: ...the reference is valid for the lifetime 'a as defined on the impl at 5:6...
--> src/main.rs:5:6
|
5 | impl<'a> Foo<'a> {
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 6:5
--> src/main.rs:6:5
|
6 | / fn get(&self) -> &'a i32 {
7 | | self.x
8 | | }
| |_____^
Why does that happen? As far as I see it, nothing about the lifetimes has changed: all values/references still live exactly as long as in the first code snippet.
Why does the Rust compiler reject this implementation of get? Because it allows:
The following is a perfectly reasonable main, assuming that get compiles:
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let a = y.get();
let b = y.x;
println!("{} {}", a, b);
}
Yet if get were to compile, this would be fine:
a does not borrow y because the lifetime is different
b "consumes" y (moving from y.x) but we do not reuse it after
So everything is fine, except that we now have a &i32 and &mut i32 both pointing to x.
Note: to make it compile, you can use unsafe inside of get: unsafe { std::mem::transmute(&*self.x) }; scary, eh?
At the heart of the borrow-checking algorithm is the cornerstone on which Rust's memory safety is built:
Aliasing XOR Mutability
Rust achieves memory safety without garbage collection by guaranteeing that whenever you are modifying something, no observer can have a reference inside that something that could become dangling.
This, in turns, lets us interpret:
&T as an aliasing reference; it is Copy
&mut T as a unique reference; it is NOT Copy, as it would violate uniqueness, but it can be moved
This difference saved us here.
Since &mut T cannot be copied, the only way to go from &mut T to &T (or &mut T) is to perform a re-borrowing: dereference and take a reference to the result.
This is done implicitly by the compiler. Doing it manually makes for a somewhat better error message:
fn get<'b>(&'b self) -> &'a i32 {
&*self.x
}
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> <anon>:7:9
|
7 | &*self.x
| ^^^^^^^^
|
help: consider using an explicit lifetime parameter as shown: fn get(&'a self) -> &'a i32
--> <anon>:6:5
|
6 | fn get<'b>(&'b self) -> &'a i32 {
| ^
Why cannot it infer a lifetime? Because lifetime of the re-borrow is limited by 'b but we are requiring a 'a and there's no relationship between the two!
By the way, this is what is saving us from blunder here, because it ensures that the instance Foo must be borrowed while the result lives (preventing us to use a mutable reference via Foo::x).
Following the compiler hint, and returning &'b i32 works... and prevents the above main from compiling:
impl<'a> Foo<'a> {
fn get<'b>(&'b self) -> &'b i32 {
&*self.x
}
}
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let a = y.get();
let b = y.x;
println!("{} {}", a, b);
}
error[E0505]: cannot move out of `y.x` because it is borrowed
--> <anon>:16:9
|
15 | let a = y.get();
| - borrow of `y` occurs here
16 | let b = y.x;
| ^ move out of `y.x` occurs here
However it lets the first main compile without issue:
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let z = y.get();
println!("{}", z);
}
Prints 3.
I'd like to make the following code compile:
struct Provider {}
impl Provider {
fn get_string<'a>(&'a self) -> &'a str { "this is a string" }
}
fn main() {
let provider = Provider{};
let mut vec: Vec<&str> = Vec::new();
// PROBLEM: how do I say that this reference s here
// needs to live as long as vec?
let fun = |s: &str| {
vec.push(s);
};
fun(provider.get_string());
}
Playground link
This is the compile error that I get:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:9:22
|
9 | let mut vec: Vec<&str> = Vec::new();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 11:24...
--> src/main.rs:11:25
|
11| let fun = |s: &str| {
| ^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:12:18
|
12| vec.push(s);
| ^
note: but, the lifetime must be valid for the block suffix following statement 2 at 13:6...
--> src/main.rs:13:7
|
13| };
| ^
note: ...so that variable is valid at time of its declaration
--> src/main.rs:11:9
|
11| let fun = |s: &str| {
| ^^^
Your code works just fine if remove all the lifetime annotations and let the compiler inference do its job:
struct Provider;
impl Provider {
fn get_string(&self) -> &str { "this is a string" }
}
fn main() {
let provider = Provider;
let mut vec = Vec::new();
let mut fun = |s| {
vec.push(s);
};
fun(provider.get_string());
}
In short, there's no way to explicitly refer to the lifetime of a local variable, only function arguments. The compiler knows how to do it, though.
If you truly needed it, you could create a function to allow annotating the lifetimes:
fn thing<'a>(provider: &'a Provider) -> Vec<&'a str> {
let mut vec: Vec<&'a str> = Vec::new();
{
let mut fun = |s: &'a str| vec.push(s);
fun(provider.get_string());
} // End mutable borrow of `vec`
vec
}
fn main() {
let provider = Provider;
thing(&provider);
}
why did the original annotations stop things from working?
Specifically, it's this bit:
let fun = |s: &str| {
vec.push(s);
};
This declares a new lifetime on the closure. Using a made-up syntax (you can't declare lifetimes on closure arguments), it would be equivalent to:
let fun = <'a> |s: &'a str| {
vec.push(s);
};
Which is why the compiler has the error:
the lifetime cannot outlive the anonymous lifetime #1 defined on [the closure's block]
There's no connection between that generated lifetime and that of the Provider. Leaving it out allows the compiler to insert the desired but unnamable lifetime.
Here's a version which compiles:
use std::marker::PhantomData;
struct Provider<'a> {
_dummy: PhantomData<&'a ()>,
}
impl<'a> Provider<'a> {
fn get_string(&self) -> &'a str {
"this is a string"
}
}
fn f<'b>() {
let provider = Provider { _dummy: PhantomData };
let mut vec: Vec<&str> = Vec::new();
// PROBLEM: how do I say that this reference s here
// needs to live as long as vec?
let mut fun = |s: &'b str| { vec.push(s); };
fun(provider.get_string());
}
fn main() {
f()
}
Playground link
I made the following changes:
Add a lifetime to Provider (I added a PhantomData, but I guess your provider already owns some data it'll provide).
Update the get_string method to show that it returns something with the provider's lifetime, not the input lifetime (ie based on the Provider's lifetime parameter).
Add a new lifetime parameter 'b to the function (which I renamed to f(), since main() can't have one), which I use to name the lifetime of the closure parameter.
The last one is slightly confusing, as apparently merely adding a name to a lifetime (without apparently adding any constraints) has made it work.
I think (but I'd love some documentation for this) that this is because of lifetime elision. A closure is really a hidden struct with a fn call(&self, s: &str) (in this case) method. According to the lifetime elision rules, the s parameter gains the same lifetime as &self, which is the closure itself. In this case, the closure is declared after vec, so the lifetime is too short. The explicit lifetime means that it is decoupled from the closure's own lifetime.
This code works fine (Playground):
struct F<'a> {
x: &'a i32,
}
impl<'a> F<'a> {
fn get<'b>(&'b self) -> &'a i32 {
self.x
}
}
fn main() {
let x = 3;
let y = F { x: &x };
let z = y.get();
}
But when I change x to be a mutable reference instead (Playground):
struct Foo<'a> {
x: &'a mut i32, // <-- `mut` added
}
impl<'a> Foo<'a> {
fn get(&self) -> &'a i32 {
self.x
}
}
fn main() {
let mut x = 3; // <-- `mut` added
let y = Foo { x: &mut x }; // <-- `mut` added
let z = y.get();
}
I get this error:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/main.rs:7:9
|
7 | self.x
| ^^^^^^
|
note: ...the reference is valid for the lifetime 'a as defined on the impl at 5:6...
--> src/main.rs:5:6
|
5 | impl<'a> Foo<'a> {
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 6:5
--> src/main.rs:6:5
|
6 | / fn get(&self) -> &'a i32 {
7 | | self.x
8 | | }
| |_____^
Why does that happen? As far as I see it, nothing about the lifetimes has changed: all values/references still live exactly as long as in the first code snippet.
Why does the Rust compiler reject this implementation of get? Because it allows:
The following is a perfectly reasonable main, assuming that get compiles:
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let a = y.get();
let b = y.x;
println!("{} {}", a, b);
}
Yet if get were to compile, this would be fine:
a does not borrow y because the lifetime is different
b "consumes" y (moving from y.x) but we do not reuse it after
So everything is fine, except that we now have a &i32 and &mut i32 both pointing to x.
Note: to make it compile, you can use unsafe inside of get: unsafe { std::mem::transmute(&*self.x) }; scary, eh?
At the heart of the borrow-checking algorithm is the cornerstone on which Rust's memory safety is built:
Aliasing XOR Mutability
Rust achieves memory safety without garbage collection by guaranteeing that whenever you are modifying something, no observer can have a reference inside that something that could become dangling.
This, in turns, lets us interpret:
&T as an aliasing reference; it is Copy
&mut T as a unique reference; it is NOT Copy, as it would violate uniqueness, but it can be moved
This difference saved us here.
Since &mut T cannot be copied, the only way to go from &mut T to &T (or &mut T) is to perform a re-borrowing: dereference and take a reference to the result.
This is done implicitly by the compiler. Doing it manually makes for a somewhat better error message:
fn get<'b>(&'b self) -> &'a i32 {
&*self.x
}
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> <anon>:7:9
|
7 | &*self.x
| ^^^^^^^^
|
help: consider using an explicit lifetime parameter as shown: fn get(&'a self) -> &'a i32
--> <anon>:6:5
|
6 | fn get<'b>(&'b self) -> &'a i32 {
| ^
Why cannot it infer a lifetime? Because lifetime of the re-borrow is limited by 'b but we are requiring a 'a and there's no relationship between the two!
By the way, this is what is saving us from blunder here, because it ensures that the instance Foo must be borrowed while the result lives (preventing us to use a mutable reference via Foo::x).
Following the compiler hint, and returning &'b i32 works... and prevents the above main from compiling:
impl<'a> Foo<'a> {
fn get<'b>(&'b self) -> &'b i32 {
&*self.x
}
}
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let a = y.get();
let b = y.x;
println!("{} {}", a, b);
}
error[E0505]: cannot move out of `y.x` because it is borrowed
--> <anon>:16:9
|
15 | let a = y.get();
| - borrow of `y` occurs here
16 | let b = y.x;
| ^ move out of `y.x` occurs here
However it lets the first main compile without issue:
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let z = y.get();
println!("{}", z);
}
Prints 3.
use std::rc::Rc;
fn f1(cb: Box<Fn(i32) -> i32>) {
let res = cb(15);
println!("res {}", res);
}
fn main() {
let mut v2 = Rc::new(5_i32);
// 1
// f1(Box::new(move |x: i32| *v2 + x));
// 2
f1(Box::new(move |x: i32| {
let tmp = *v2;
*Rc::get_mut(&mut v2).unwrap() = tmp + 1;
x + *v2
}));
}
The code referenced as "1", if uncommented, compiles and runs just fine, but the code referenced as "2" does not compile, failing with the message:
error[E0596]: cannot borrow `v2` as mutable, as it is a captured variable in a `Fn` closure
How can I fix this, if I want keep the code structure as it is?
In my real code, I want connect two traits. One of them will call a callback on event, and the other has a function to handle the callback:
trait Foo {
fn add_callback(&mut self, cb: Box<Fn(i32)>);
}
trait Boo {
fn on_new_data(&mut self, data: i32);
}
I want to create a trait object with Boo, wrap it with Rc, and pass it to Foo::add_callback in the form of |x:i32| Rc::get_mut(&mut boo).unwrap().on_new_data(x)
The entire error message is mostly helpful:
error[E0596]: cannot borrow `v2` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:17:19
|
17 | *Rc::get_mut(&mut v2).unwrap() = tmp + 1;
| ^^^^^^^ cannot borrow as mutable
|
help: consider changing this to accept closures that implement `FnMut`
--> src/main.rs:15:17
|
15 | f1(Box::new(move |x: i32| {
| _________________^
16 | | let tmp = *v2;
17 | | *Rc::get_mut(&mut v2).unwrap() = tmp + 1;
18 | | x + *v2
19 | | }));
| |_____^
Changing f1 to accept a FnMut and making the variable mutable allows the code to compile:
fn f1(mut cb: Box<FnMut(i32) -> i32>) {
This is needed in order to mutate the captured variable v2, required by the &mut v2 argument to Rc::get_mut.