返回消费 StdinLock 的结果时,为啥要保留对 stdin 的借用?

Posted

技术标签:

【中文标题】返回消费 StdinLock 的结果时,为啥要保留对 stdin 的借用?【英文标题】:When returning the outcome of consuming a StdinLock, why was the borrow to stdin retained?返回消费 StdinLock 的结果时,为什么要保留对 stdin 的借用? 【发布时间】:2017-09-21 06:10:34 【问题描述】:

给定以下函数:

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

这表明立即返回“已使用的锁”会导致锁尝试比被锁定的内容更长的时间,这很不寻常。我研究的所有引用通常都指出声明的顺序很重要,但返回的对象如何影响它们被释放的顺序并不重要。

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

【问题讨论】:

哦。有趣! 有人提出错误报告吗? @Veedrac:我不是不知道,我一直在寻找解释,因为经验一次又一次地证明借用检查器比我的直觉更可靠。再说一次,在这种情况下,看起来越来越有可能发生了什么可疑的事情...... 围绕这个主题有一些未解决的问题。主要的是github.com/rust-lang/rust/issues/37407 关于这个问题的讨论已经在#21114进行。 【参考方案1】:

我无法回答您问题的为什么,但我可以声明当前的1 实现非词法生命周期允许编译原始代码:

#![feature(nll)]

use std::io::BufRead, stdin;

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

Playground

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

【讨论】:

【参考方案2】:

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

use std::io::stdin, BufRead;

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


fn main() 

playground

如 cmets 中所述,有多个与此相关的 Rust 问题:

37407 21114

【讨论】:

以上是关于返回消费 StdinLock 的结果时,为啥要保留对 stdin 的借用?的主要内容,如果未能解决你的问题,请参考以下文章

返回executeFetchRequest的NSArray:结果时我应该保留,自动释放还是啥都不做?

为啥我们要使用开窗函数?

为啥我需要保留NSDateFormatter dateFromString的结果:

php中3个小数的计算,如134.7-52.5 - 82.2,为啥结果不是0而是一个奇怪的科学计数法?

当 XPath 验证器返回正确结果时,为啥 XmlNode.SelectNodes 返回空列表?

为啥自我实现的 getter 应该保留并自动释放返回的对象?