rust - 如何使用 Rust 类型系统来防止输出到标准输出?

标签 rust locking lifetime borrow-checker borrowing

我正在开发一个数据管道节点,一个应用程序从 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的生​​命周期
  • 句柄添加显式类型和生命周期注解
  • io::stdout() 声明一个变量并用类型和生命周期进行注释
  • 为闭包添加明确的类型和生命周期注释
  • 声明一个本地函数而不是使用闭包,无法捕获环境
  • 在闭包上使用move 语义,不是最明智的举动,但我正在捕获救命稻草

最佳答案

你不能。标准输出锁是reentrant :

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

再多的类型调整也无法阻止同一个线程重新获取标准输出/错误锁并在输出中间进行打印。


您的编译器错误通过以下方式解决:

关于rust - 如何使用 Rust 类型系统来防止输出到标准输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53230295/

相关文章:

rust - 无法分配,因为它是在返回包含引用的 Result 的结构的方法中借用的

c - 在用户空间应用程序中使用自旋锁

php - mysql查询锁定数据库

c++ - 不死物体 ([basic.life]/8) : why is reference rebinding (and const modification) allowed?

struct - '&self'和 '&' a self'有什么区别?

rust - 在 Rust 中指定数组大小时,C 的 #define 等效于什么?

python - 为了使用 Python 从 Rust 程序内部调用函数,应遵循的最佳实践是什么?

sql - 设置 deadlock_priority 不会使低优先级 session 成为受害者

iterator - 从通用关联函数返回对值的引用的合适方法是什么?

loops - E0597试图在向量上循环