问题
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?
回答1:
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);
}
}
回答2:
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);
}
}
回答3:
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 ...
来源:https://stackoverflow.com/questions/56724730/create-closure-returning-iterator-on-string