当返回使用StdinLock时的结果时,为什么stdin的借用被保留了?

17

考虑下面的函数:

use std::io::{BufRead, stdin};

fn foo() -> usize {
    let stdin = stdin();
    let stdinlock = stdin.lock();
    stdinlock
        .lines()
        .count()
}

使用以下错误无法通过编译:

error: `stdin` does not live long enough
  --> src/main.rs:12:1
   |
7  |     let stdinlock = stdin.lock();
   |                     ----- borrow occurs here
...
11 | }
   | ^ `stdin` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

我觉得这很令人惊讶,因为通过锁(通过lines)消耗的结果并不保留对原始来源的任何引用。实际上,在返回之前将相同的结果分配给绑定变量也可以正常工作(Playground)。

fn bar() -> usize {
    let stdin = stdin();
    let stdinlock = stdin.lock();
    let r = stdinlock
        .lines()
        .count();
    r
}

这表明立即返回一个“已消耗的锁”导致锁试图以一种不寻常的方式比锁定的内容更长时间地存在。我查阅的所有参考资料通常指出声明顺序很重要,但没有说明返回的对象如何影响它们释放的顺序。

那么为什么编译器会拒绝前面的函数呢?为什么锁似乎被保留的时间比预期要长?


1
哦,有趣! - Matthieu M.
@MatthieuM。原因似乎在MutexGuard周围有一些神奇的东西。我根据类型做了一个过度简化的复制,点击这里。在崩溃的版本中,我使用了来自stdMutexGuard。在正常工作的版本中,我复制粘贴了相同的代码而不是使用std - Peter Hall
1
有人提出了错误报告吗? - Veedrac
1
@Veedrac:据我所知并没有,我在寻找一个解释,因为经验一次又一次地证明借用检查器比我的直觉更可靠。然而,在这种情况下,看起来越来越有可能出现一些问题... - Matthieu M.
5
这个话题还有一些未解决的问题。主要问题是 https://github.com/rust-lang/rust/issues/37407 。 - oli_obk
2
关于这个问题的讨论已经在#21114进行了。 - E net4
2个回答

3

这似乎是编译器中的一个bug。您可以通过使用显式的return语句让编译器满意:

use std::io::{stdin, BufRead};

fn foo() -> usize {
    let stdin = stdin();
    let stdinlock = stdin.lock();
    return stdinlock
        .lines()
        .count();
}

fn main() {}

Playground

正如在评论中提到的那样,这与 Rust 相关的问题有多个:


2

我无法回答你问题中的“为什么”,但是我可以说明当前非词汇生命周期实现允许原始代码编译:

#![feature(nll)]

use std::io::{BufRead, stdin};

fn foo() -> usize {
    let stdin = stdin();
    let stdinlock = stdin.lock();
    stdinlock
        .lines()
        .count()
}

游乐场

1 1.25.0-nightly (2018-01-11 73ac5d6)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接