有没有一种方法可以在构造函数中使用锁定的标准输入和输出,直到您要构造的结构生存? [英] Is there a way to use locked standard input and output in a constructor to live as long as the struct you're constructing?

查看:113
本文介绍了有没有一种方法可以在构造函数中使用锁定的标准输入和输出,直到您要构造的结构生存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个PromptSet,它可以连续询问一系列问题.出于测试原因,它使您可以通过读写器,而不必使用stdin&直接输出.

I'm building a PromptSet that can ask a series of questions in a row. For testing reasons, it allows you to pass a reader and writer instead of using stdin & stdout directly.

因为stdin和stdout是常见的用例,所以我想创建一个默认的构造函数",使用户无需任何参数即可生成PromptSet<StdinLock, StdoutLock>.到目前为止,这是代码:

Because stdin and stdout are the common use case, I would like to create a default "constructor" that allows the user to produce a PromptSet<StdinLock, StdoutLock> without needing any parameters. Here's the code so far:

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() {}

StdinLockStdoutLock都需要声明一个生存期.为了使其复杂化,我认为原始的stdin()/stdout()句柄需要至少与锁一样长寿.我希望对StdinLockStdoutLock的引用能够一直存在,只要我的PromptSet可以,但是无论我尝试什么,都无法使其正常工作.这是我不断收到的错误:

StdinLock and StdoutLock both need a lifetime declared. To complicate it, I think the original stdin()/stdout() handles need to live at least as long as the locks do. I would like the references to StdinLock and StdoutLock to live as long as my PromptSet does but no matter what I try I can't get it to work. Here is the error that I keep getting:

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 | |     }
   | |_____^

很可能我只是不了解生命周期或其他一些超基本的概念.

It's perfectly possible I just don't understand the concept of lifetimes or something else super basic.

推荐答案

lock方法的签名为fn lock(&self) -> StdinLock,当使用生命周期注释完全扩展时,其签名为fn lock<'a>(&'a self) -> StdinLock<'a>.因此,StdinLock的生存时间只能与调用lock方法的值一样长.由于您在此函数中定义了stdin,因此StdinLock不能超过该功能.这与返回对本地值的引用相同.您还不能一起返回引用和引用值.

The lock method's signature is fn lock(&self) -> StdinLock, which, when fully expanded with lifetime annotations, is fn lock<'a>(&'a self) -> StdinLock<'a>. Thus the StdinLock can only live as long as the value that the lock method is called on. Since you defined stdin in this very function, the StdinLock can't outlive the function. This is the same as returning a reference to a local value. You also can't return the reference and the referred-to value together.

您无法执行此操作,也无法解决该问题.唯一的解决方法是让default方法将StdinStdout对象作为参数.

You can't do this, and you can't work around it. The only fix is to have the default method take a Stdin and a Stdout object as arguments.

也就是说,您可以解决它.是的,我知道,我只是说了完全相反的意思,但这更多的是没有人会使用stdin/stdout".(又名println!将不再起作用!).

That said, you can work around it. Yes I know, I just said the exact opposite, but it's more of a "no one other than me will ever use stdin/stdout" (a.k.a., println! will not work anymore!).

在Rust 1.26中,您可以使用 Stdin泄漏到&'static Stdin,这将产生StdinLock<'static>.在Rust 1.26之前,您可以使用 leak 条板箱:

In Rust 1.26, you can use Box::leak to leak the Stdin to a &'static Stdin, which will yield a StdinLock<'static>. Before Rust 1.26, you can use the leak crate:

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(),
    }
}

这篇关于有没有一种方法可以在构造函数中使用锁定的标准输入和输出,直到您要构造的结构生存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆