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

问题描述:

鉴于以下功能:当返回使用StdinLock的结果时,为什么要保留stdin的借用?

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

哦。有趣! –

+0

@MatthieuM。原因似乎是'MutexGuard'的魔法。我仅仅根据类型做了一个简单的复制。见[这里](https://gist.github.com/peterjoel/f6a1e1ec29da1ee73994820f742cdb7d#file-stlocklock_problem-rs)。在破解的版本中,我使用'std'中的'MutexGuard'。在工作的版本中,我复制粘贴相同的代码而不是使用'std'。 –

+1

有没有人提出过错误报告? – Veedrac

这似乎是编译器中的一个错误。你可以让编译器高兴通过使用一个明确的return声明:

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

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

fn main() {} 

playground

正如在评论中提到的,也有与此相关的多种锈病问题:

我不能回答你的问题的为什么,但我可以说,当前实现非词汇寿命的允许原始代码进行编译:

​​3210

Playground

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