有没有办法在构造函数中使用锁定的标准输入和输出,只要你正在构造的结构生存?

web*_*rts 1 stdin stdout lifetime rust

我正在建立一个PromptSet可以连续问一系列问题的人.出于测试原因,它允许您传递读写器而不是直接使用stdin和stdout.

因为stdin和stdout是常见的用例,所以我想创建一个默认的"构造函数",允许用户生成一个PromptSet<StdinLock, StdoutLock>不需要任何参数.这是迄今为止的代码:

use std::io::{self, BufRead, StdinLock, StdoutLock, Write};

pub struct PromptSet<R, W>
where
    R: BufRead,
    W: Write,
{
    pub reader: R,
    pub writer: W,
}

impl<R, W> PromptSet<R, W>
where
    R: BufRead,
    W: Write,
{
    pub fn new(reader: R, writer: W) -> PromptSet<R, W> {
        return PromptSet {
            reader: reader,
            writer: writer,
        };
    }

    pub fn default<'a>() -> PromptSet<StdinLock<'a>, StdoutLock<'a>> {
        let stdin = io::stdin();
        let stdout = io::stdout();

        return PromptSet {
            reader: stdin.lock(),
            writer: stdout.lock(),
        };
    }

    pub fn prompt(&mut self, question: &str) -> String {
        let mut input = String::new();

        write!(self.writer, "{}: ", question).unwrap();
        self.writer.flush().unwrap();
        self.reader.read_line(&mut input).unwrap();

        return input.trim().to_string();
    }
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

StdinLock并且StdoutLock都需要终生宣布.为了使它复杂化,我认为原始stdin()/ stdout()句柄需要至少与锁一样长.我希望参考StdinLockStdoutLock生活只要我PromptSet做,但无论我尝试什么,我都无法让它工作.这是我一直得到的错误:

error[E0597]: `stdin` does not live long enough
  --> src/main.rs:30:21
   |
30 |             reader: stdin.lock(),
   |                     ^^^^^ borrowed value does not live long enough
...
33 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the method body at 25:5...
  --> src/main.rs:25:5
   |
25 | /     pub fn default<'a>() -> PromptSet<StdinLock<'a>, StdoutLock<'a>> {
26 | |         let stdin = io::stdin();
27 | |         let stdout = io::stdout();
28 | |
...  |
32 | |         };
33 | |     }
   | |_____^

error[E0597]: `stdout` does not live long enough
  --> src/main.rs:31:21
   |
31 |             writer: stdout.lock(),
   |                     ^^^^^^ borrowed value does not live long enough
32 |         };
33 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the method body at 25:5...
  --> src/main.rs:25:5
   |
25 | /     pub fn default<'a>() -> PromptSet<StdinLock<'a>, StdoutLock<'a>> {
26 | |         let stdin = io::stdin();
27 | |         let stdout = io::stdout();
28 | |
...  |
32 | |         };
33 | |     }
   | |_____^
Run Code Online (Sandbox Code Playgroud)

我完全有可能不理解生命的概念或其他超基本的概念.

oli*_*obk 5

lock方法的签名是fn lock(&self) -> StdinLock,当使用生命周期注释完全展开时,是fn lock<'a>(&'a self) -> StdinLock<'a>.因此,StdinLock只有lock调用方法的值才能生存.既然你stdin在这个函数中定义了,StdinLock就不能比这个函数活得更久了.这与返回对本地值的引用相同.您也无法将引用和引用的值一起返回.

你不能这样做,你不能解决它.唯一的解决default方法是让方法将a StdinStdout对象作为参数.

也就是说,你可以解决它.是的,我知道,我只是说完全相反,但更多的是"除了我以外没有人会使用stdin/stdout" (又名,println!不再适用了!).

在Rust 1.26中,您可以使用Box::leak泄漏Stdin到a &'static Stdin,这将产生一个StdinLock<'static>.在Rust 1.26之前,您可以使用leak包:

pub fn default() -> PromptSet<StdinLock<'static>, StdoutLock<'static>> {
    let stdin = Box::leak(Box::new(io::stdin()));
    let stdout = Box::leak(Box::new(io::stdout()));

    PromptSet {
        reader: stdin.lock(),
        writer: stdout.lock(),
    }
}
Run Code Online (Sandbox Code Playgroud)