简体   繁体   English

如何借用检查“impl Trait”类型的返回值?

[英]How are return values of type `impl Trait` borrow-checked?

The following code fails to compile:以下代码无法编译:

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

It compiles if I replace foo 's signature with如果我将foo的签名替换为

fn foo<'a, F: Fn() -> &'a str>(vec: Vec<i32>, fun: F) -> <Vec<i32> as IntoIterator>::IntoIter {
    // ...
}

It makes me believe that impl Trait types are borrow-checked more conservatively: the compiler assumes that the returned object captures fun even though it doesn't.这让我相信impl Trait类型被更保守地借用检查:编译器假设返回的对象捕获fun即使它没有。

However, this interesting example compiles fine:然而,这个有趣的例子编译得很好:

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);
    }
}

Here the compiler seems not to assume that the returned impl Iterator<Item = i32> borrows s .这里编译器似乎没有假设返回的impl Iterator<Item = i32>借用了s

How exactly are returned impl Trait types borrow-checked?返回的impl Trait类型借用检查究竟如何? When are they assumed to borrow other function arguments, like in the first case?他们什么时候假设借用其他函数参数,就像在第一种情况下一样? When are they assumed not to, like in the latter case?什么时候假设他们不这样做,就像在后一种情况下一样?

I believe this issue comment tells the story here.我相信这个问题评论在这里讲述了故事。 It sounds like it's an intentional limitation of the type system to be conservative, but I agree with the issue author that this would be good to be able to opt out of:听起来像保守的类型系统的故意限制,但我同意问题作者的观点,能够选择退出会很好:

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.这种行为的核心原因是 impl Trait 在返回位置的变化行为:返回的 impl Trait 始终是所有通用输入参数的变体,即使没有在技术上使用。 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.这样做是为了如果您更改返回impl Trait的公共 API 的内部实现,您不必担心向 API 引入额外的差异参数。 This could break downstream code and is thus not desireable for Rust's semver system.这可能会破坏下游代码,因此对于 Rust 的 semver 系统来说是不可取的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM