以下代码无法编译:
fn foo<'a, F: Fn() -> &'a str>(vec: Vec<i32>, fun: F) -> impl Iterator<Item = i32> {
println!("{}", fun());
vec.into_iter()
}
fn main() {
let s = "hello, world!".to_string();
let iter = foo(vec![1, 2, 3], || &s);
drop(s);
for x in iter {
println!("{}", x);
}
}
error[E0505]: cannot move out of `s` because it is borrowed
--> src/main.rs:9:10
|
8 | let iter = foo(vec![1, 2, 3], || &s);
| -- - borrow occurs due to use in closure
| |
| borrow of `s` occurs here
9 | drop(s);
| ^ move out of `s` occurs here
10 |
11 | for x in iter {
| ---- borrow later used here
如果我替换 foo
,它会编译的签名与fn foo<'a, F: Fn() -> &'a str>(vec: Vec<i32>, fun: F) -> <Vec<i32> as IntoIterator>::IntoIter {
// ...
}
这让我相信 impl Trait
类型的借用检查更为保守:编译器假定返回的对象捕获 fun
即使没有。然而,这个有趣的例子编译得很好:
fn foo(s: &str) -> impl Iterator<Item = i32> {
println!("{}", s);
vec![1, 2, 3].into_iter()
}
fn main() {
let s = "hello, world!".to_string();
let iter = foo(&s);
drop(s);
for x in iter {
println!("{}", x);
}
}
这里编译器似乎没有假设返回的 impl Iterator<Item = i32>
借s
.如何准确返回
impl Trait
类型借检查?他们什么时候假设借用其他函数参数,就像在第一种情况下一样?什么时候假设他们不这样做,就像在后一种情况下一样?
最佳答案
我相信 this issue comment讲述这里的故事。听起来像保守的类型系统的故意限制,但我同意问题作者的观点,能够选择退出会很好:
The core reason for this behaviour is the variance behaviour of impl Trait in return position: the returned impl Trait is always variant over all generic input parameters, even if not technically used. This is done so that if you change the internal implementation of a public API returning
impl Trait
you don't have to worry about introducing an additional variance param to the API. This could break downstream code and is thus not desireable for Rust's semver system.
关于rust - 如何检查 `impl Trait` 类型的返回值借用检查?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68143578/