Когда возвращался результат потребления 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) не содержит ссылок на исходный источник. Фактически, присвоение того же результата привязке перед возвратом работает просто отлично (Игровая площадка).

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

Это говорит о том, что немедленное возвращение "потребляемой блокировки" привело к тому, что блокировка, пытающаяся жить дольше заблокированного контента, необычно. Все ссылки, на которые я смотрел, обычно указывают на то, что порядок декларирования имеет значение, но не как возвращаемые объекты могут влиять на порядок, в котором они выпущены.

Итак, почему первая функция отвергается компилятором? Почему блокировка кажется сохраненной дольше, чем ожидалось?

Ответы

Ответ 1

Кажется, это ошибка в компиляторе. Вы можете сделать компилятор счастливым, используя явную инструкцию return:

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

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

fn main() {}

игровая площадка

Как упоминалось в комментариях, существует несколько проблем Rust, связанных с этим:

Ответ 2

Я не могу ответить на вопрос о том, почему ваш вопрос, но могу утверждать, что текущая реализация несексных времен жизни 1 позволяет скомпилировать исходный код:

#![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)