我不知道为什么这个简单的例子不起作用:
use std::io;
use std::io::prelude::*;
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
match line {
Ok(val) => match val {
v @ _ => println!("{:?}", v),
"q" => std::process::exit(0)
},
_ => println!("ERROR")
}
}
}
错误是:
src/main.rs:8:5: 16:6 error: type mismatch resolving `<std::io::Lines<std::io::stdio::StdinLock<'_>> as core::iter::Iterator>::Item == core::result::Result<&str, _>`:
expected struct `collections::string::String`,
found &-ptr [E0271]
src/main.rs: 8 for line in stdin.lock().lines() {
src/main.rs: 9 match line {
src/main.rs:10 Ok(val) => match val {
src/main.rs:11 v @ _ => println!("{:?}", v),
src/main.rs:12 "q" => std::process::exit(0)
src/main.rs:13 },
...
我只是想回显输入的stdin行,如果行等于“q”则退出应用程序。
答案 0 :(得分:2)
这个稍微令人困惑的错误消息是Rust执行类型推断的方法的结果。当它查看循环的第一行时,Rust不知道line
具有什么类型。所以它试图弄清楚循环体:
match line {
Ok(val) => /* ... */
_ => /* ... /*
}
使用此信息rustc
知道line
的类型至少为Result<_, _>
,其中_
是编译器仍然不知道的类型。所以它试图找出最后一点:
Ok(val) => match val {
v @ _ => println!("{:?}", v),
"q" => std::process::exit(0)
},
绑定val
对应Result
的第一个类型参数。那么这里的val
是什么。您将val
与"q"
匹配。后一个表达式的类型为&str
,因此编译器假定val
的类型为&str
。因此line
类型Result<&str, _>
(_
仍然未知,但现在无关紧要。)
现在rustc
试图找出如何使用stdin.lock().lines()
的结果作为产生Result<&str, _>
的迭代器。这对编译器来说是不可能的,因为std::io::Lines
总是产生Result<String, io::Error>
。
要获得更好的错误消息,可以显式声明迭代器的类型(在这种情况下:重新绑定它):
for line in stdin.lock().lines() {
let line: io::Result<String> = line;
// ...
}
这导致
<anon>:12:17: 12:20 error: mismatched types: expected `collections::string::String`, found `&'static str` (expected struct `collections::string::String`, found &-ptr) [E0308] <anon>:12 "q" => std::process::exit(0), ^~~
显然有很多解决方案。在这里你可以看到我喜欢的一个,因为它有助于rustc
自己找出类型:
for line in stdin.lock().lines() {
match line {
Ok(val) => match val.as_str() { // <-- note the `as_str()`
"q" => std::process::exit(0),
v @ _ => println!("{:?}", v),
},
_ => println!("ERROR")
}
}
(我也将"q"
手臂移至顶部 - 否则无法访问)
答案 1 :(得分:1)
在匹配字符串时...您需要将其切片以匹配字符串文字,因为您尝试将String
与&str
匹配。
Ok(val) => match &val[..] { // <---- note the ampersand and the square brackets with two dots inside
此外,一旦执行此操作,编译器可能会抱怨您的"q"
模式无法访问。这是因为你的“全能”(下划线)在明确的"q"
匹配之前......所以只需重新排序它们。
变成:
match line {
Ok(val) => match &val[..] {
// The lines below are re-ordered
"q" => std::process::exit(0),
v @ _ => println!("{:?}", v)
},
_ => println!("ERROR")
}
答案 2 :(得分:1)
问题是编译器正在尝试将val
与String
匹配,而"q"
模式是&str
。这会让你感到不匹配。
相反,请写match val.as_str()
以使类型匹配。也许将字符串文字转换为String
也可以,但这将是一个无用的堆分配。
其次,模式v @ _
是多余的。你说的是“匹配任何内容,并将其命名为v
”。但是一个简单的v
模式可以做同样的事情。