有没有一种方法可以在构造函数中使用锁定的标准输入和输出,使其与您正在构造的结构一样长?
Is there a way to use locked standard input and output in a constructor to live as long as the struct you're constructing?
我正在构建一个可以连续提出一系列问题的 PromptSet
。出于测试原因,它允许您传递 reader 和编写器,而不是直接使用标准输入和标准输出。
因为 stdin 和 stdout 是常见的用例,我想创建一个默认值 "constructor",允许用户生成 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() {}
StdinLock
和 StdoutLock
都需要声明生命周期。更复杂的是,我认为原始的 stdin()
/stdout()
句柄需要至少与锁一样长。我希望对 StdinLock
和 StdoutLock
的引用与我的 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 | | }
| |_____^
我完全有可能不理解生命周期的概念或其他超级基础的概念。
lock
方法的签名是 fn lock(&self) -> StdinLock
,当使用生命周期注释完全扩展时,它是 fn lock<'a>(&'a self) -> StdinLock<'a>
。因此,StdinLock
只能与调用 lock
方法的值一样长。由于您在此函数中定义了 stdin
,因此 StdinLock
无法比该函数更有效。这与 returning a reference to a local value. You also .
相同
你不能这样做,也无法解决它。唯一的解决方法是让 default
方法将 Stdin
和 Stdout
对象作为参数。
也就是说,您可以解决它。是的,我知道,我刚刚说的恰恰相反,但它更像是 "no one other than me will ever use stdin/stdout" (a.k.a., println!
将不再起作用!) .
在 Rust 1.26 中,您可以使用 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(),
}
}
可能不是您问题的真正答案,而是类似问题的答案。这是我的解决方案。
这里的主要技巧是为每一行调用 stdin.lock()
。
use std::io;
use std::io::prelude::*;
use std::io::Stdin;
struct StdinWrapper {
stdin: Stdin,
}
impl Iterator for StdinWrapper {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
let stdin = &self.stdin;
let mut lines = stdin.lock().lines();
match lines.next() {
Some(result) => Some(result.expect("Cannot read line")),
None => None,
}
}
}
/**
* Callers of this method should not know concrete source of the strings.
* It could be Stdin, a file, DB, or even aliens from SETI.
*/
fn read() -> Box<Iterator<Item = String>> {
let stdin = io::stdin();
Box::new(StdinWrapper { stdin })
}
fn main() {
let lines = read();
for line in lines {
println!("{}", line);
}
}
我正在构建一个可以连续提出一系列问题的 PromptSet
。出于测试原因,它允许您传递 reader 和编写器,而不是直接使用标准输入和标准输出。
因为 stdin 和 stdout 是常见的用例,我想创建一个默认值 "constructor",允许用户生成 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() {}
StdinLock
和 StdoutLock
都需要声明生命周期。更复杂的是,我认为原始的 stdin()
/stdout()
句柄需要至少与锁一样长。我希望对 StdinLock
和 StdoutLock
的引用与我的 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 | | }
| |_____^
我完全有可能不理解生命周期的概念或其他超级基础的概念。
lock
方法的签名是 fn lock(&self) -> StdinLock
,当使用生命周期注释完全扩展时,它是 fn lock<'a>(&'a self) -> StdinLock<'a>
。因此,StdinLock
只能与调用 lock
方法的值一样长。由于您在此函数中定义了 stdin
,因此 StdinLock
无法比该函数更有效。这与 returning a reference to a local value. You also
你不能这样做,也无法解决它。唯一的解决方法是让 default
方法将 Stdin
和 Stdout
对象作为参数。
也就是说,您可以解决它。是的,我知道,我刚刚说的恰恰相反,但它更像是 "no one other than me will ever use stdin/stdout" (a.k.a., println!
将不再起作用!) .
在 Rust 1.26 中,您可以使用 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(),
}
}
可能不是您问题的真正答案,而是类似问题的答案。这是我的解决方案。
这里的主要技巧是为每一行调用 stdin.lock()
。
use std::io;
use std::io::prelude::*;
use std::io::Stdin;
struct StdinWrapper {
stdin: Stdin,
}
impl Iterator for StdinWrapper {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
let stdin = &self.stdin;
let mut lines = stdin.lock().lines();
match lines.next() {
Some(result) => Some(result.expect("Cannot read line")),
None => None,
}
}
}
/**
* Callers of this method should not know concrete source of the strings.
* It could be Stdin, a file, DB, or even aliens from SETI.
*/
fn read() -> Box<Iterator<Item = String>> {
let stdin = io::stdin();
Box::new(StdinWrapper { stdin })
}
fn main() {
let lines = read();
for line in lines {
println!("{}", line);
}
}