我尝试运行以下代码段:
let a = &[Some(1), Some(2), Some(3), None, Some(4)];
let mut sum = 0;
for &Some(x) in a.iter() {
sum += x;
}
assert_eq!(sum, 1+2+3+4);
编译器回复:
about_loops.rs:39:9: 43:18 error: non-exhaustive patterns: None not covered
about_loops.rs:39 for &Some(x) in a.iter() {
about_loops.rs:40 sum += x;
about_loops.rs:41 }
about_loops.rs:42
about_loops.rs:43 assert_eq!(sum, 1+2+3+4);
error: aborting due to previous error
make: *** [all] Error 101
我是否可以在不使用luke和hobbs建议的匹配表达式的情况下为for循环编译这样的构造?或者此错误消息是误导性的? 鉴于for的语法定义,似乎没有这样做。
for_expr : "for" pat "in" expr '{' block '}' ;
我在:
rustc 0.11.0-pre-nightly (6291955 2014-05-19 23:41:20 -0700)
host: x86_64-apple-darwin
澄清:“表达式”是多么具有表现力。 for_expr的一部分?与http://doc.rust-lang.org/rust.html#for-expressions下的定义相比,未在http://doc.rust-lang.org/rust.html#match-expressions下指定。
答案 0 :(得分:3)
for
循环的模式基本上与let
具有相同的限制:它必须是无可辩驳的,也就是说,它不能无法匹配。
无可辩驳的模式的示例是&
,元组,结构和单变量枚举。其他模式(如多变量枚举或文字)不能保证始终匹配,因为该类型允许模式未涵盖的值。
for
构造本质上是一个消解如下的宏(它在扩展宏的同一遍中去掉,你可以看到它用--pretty expanded
手动运行rustc):
for <pattern> in <iter_expression> {
<code>
}
// becomes
match &mut <iter_expression> { // match to guarantee data lives long enough
it => {
loop {
match it.next() {
None => break,
Some(<pattern>) => { <code> }
}
}
}
}
这是正常的match
,即武器必须是详尽的(涵盖所有可能性),因此如果<pattern>
只是&Some(_)
,那么Some(&None)
可能性不包括在内。
(Some
部分基本上等同于Some(value) => { let <pattern> = value; ...
。现在考虑一下,这可能实际上是一个可以提供更好错误信息的desugaring:我提交了#14390。)
答案 1 :(得分:1)
Some
是枚举中的一种类型。 Option
枚举有两种类型,Some(T)
和None
。您的代码假定a.iter()
始终为Some(T)
,并且从不检查None
。要添加支票,您可以使用match
。像这样:
let a = &[Some(1), Some(2), Some(3), None, Some(4)];
let mut sum = 0;
for &j in a.iter() {
match j {
Some(x) => sum += x,
None => ()
}
}
assert_eq!(sum, 1+2+3+4);
希望有所帮助!
答案 2 :(得分:1)
for
将a
中的每个元素绑定到模式&Some(x)
- 所以当a
的第一个元素是&Some(1)
时,x
变为1.但None
与模式&Some(x)
不匹配,因此绑定无法成功。 Rust根据a
的类型实际为Option
(包含Some(_)
或None
的类型)的字面值推断,并且您的模式不会覆盖所有的可能性。而不是等待运行时告诉你它不知道该怎么做,而是在编译时抛出错误。
从我所知道的小Rust(大部分已阅读教程)中我认为你需要做类似的事情:
for &thing in a.iter() {
match thing {
Some(x) => sum += x
None => /* do nothing */
}
}
答案 3 :(得分:1)
以下也有效:
use std::iter::AdditiveIterator;
fn main() {
let a = &[Some(1), Some(2), Some(3), None, Some(4)];
let sum = a.iter().filter_map(|x| *x).sum();
assert_eq!(sum, 1+2+3+4);
}
答案 4 :(得分:1)
这也有效:
let sum = a.iter().fold(0, |s, e| s + e.unwrap_or(0));