Как использовать систему типов Rust для предотвращения вывода на стандартный вывод? - PullRequest
0 голосов
/ 09 ноября 2018

Я работаю над узлом конвейера данных, приложением, которое непрерывно передает данные из stdin, обрабатывает их и непрерывно выводит результат в stdout в потоковом режиме.

Учитывая, что формат обмена данными предопределен, мне нужен удобный способ запретить вывод результатов отладки одновременно с передачей на стандартный вывод. По сути, глобальная блокировка. Правда, я мог бы просто избавиться от всех отладочных утверждений, но это скорее академическое упражнение.

Итак, давайте создадим функцию, которая может записывать в stdout и блокировать stdout, пока она остается в области видимости, поэтому сама система типов предотвращает запись других мест в коде в stdout:

use std::io::{self, Write};

pub fn make_push_output<'a>() -> &'a impl Fn(String) -> io::Result<()> {
    let handle = io::stdout().lock();

    &|output: String| {
        handle.write(output.to_string().as_bytes())?;

        Ok(())
    }
}

Классно, глобальная блокировка на stdout, которая остается на месте до тех пор, пока выходная функция push_output() не выйдет из области видимости, но не работает. Я получаю полный список ошибок проверки заимствования:

error[E0597]: borrowed value does not live long enough
 --> src/lib.rs:4:18
  |
4 |     let handle = io::stdout().lock();
  |                  ^^^^^^^^^^^^       - temporary value only lives until here
  |                  |
  |                  temporary value does not live long enough
  |
  = note: borrowed value must be valid for the static lifetime...

error[E0597]: borrowed value does not live long enough
  --> src/lib.rs:6:6
   |
6  |       &|output: String| {
   |  ______^
7  | |         handle.write(output.to_string().as_bytes())?;
8  | |
9  | |         Ok(())
10 | |     }
   | |_____^ temporary value does not live long enough
11 |   }
   |   - temporary value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 3:25...
  --> src/lib.rs:3:25
   |
3  | pub fn make_push_output<'a>() -> &'a impl Fn(String) -> io::Result<()> {
   |                         ^^

error[E0373]: closure may outlive the current function, but it borrows `handle`, which is owned by the current function
 --> src/lib.rs:6:6
  |
6 |     &|output: String| {
  |      ^^^^^^^^^^^^^^^^ may outlive borrowed value `handle`
7 |         handle.write(output.to_string().as_bytes())?;
  |         ------ `handle` is borrowed here
help: to force the closure to take ownership of `handle` (and any other referenced variables), use the `move` keyword
  |
6 |     &move |output: String| {
  |      ^^^^^^^^^^^^^^^^^^^^^

error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure
 --> src/lib.rs:7:9
  |
7 |         handle.write(output.to_string().as_bytes())?;
  |         ^^^^^^
  |
help: consider changing this closure to take self by mutable reference
 --> src/lib.rs:6:6
  |
6 |       &|output: String| {
  |  ______^
7 | |         handle.write(output.to_string().as_bytes())?;
8 | |
9 | |         Ok(())
10| |     }
  | |_____^

Я уже более часа пытаюсь исправить эту последовательность ошибок проверки заимствования в этих 7 строках кода. Вот неполный список шагов, которые я предпринял до сих пор, но которые не сработали:

  • Изменить время жизни make_push_output
  • Добавить явную аннотацию типа и времени жизни к handle
  • Объявление переменной для io::stdout() и аннотирование с типом и временем жизни
  • Добавить явную аннотацию типа и времени жизни к закрытию
  • Объявить локальную функцию вместо использования замыкания, не удалось захватить среду
  • Используйте move семантику на замыкании, не самый яркий ход, но я цеплялся за соломинку

1 Ответ

0 голосов
/ 09 ноября 2018

Вы не можете. Стандартная блокировка вывода входящий :

use std::io::{self, Write};

fn main() {
    let out = io::stdout();
    let mut handle = out.lock();
    writeln!(handle, "handle: {}", 1);

    println!("Debugging output");

    writeln!(handle, "handle: {}", 2);
    drop(handle)
}

Это печатает:

handle: 1
Debugging output
handle: 2

Никакое жонглирование типов не может помешать тому же потоку повторно получить блокировку для стандартного выхода / ошибки и печати в середине вашего вывода.


Ваши ошибки компилятора устраняются:

...