为何Rust中match语句None分支加花括号可使代码正常运行?
为什么Rust中match分支去掉花括号会触发类型不匹配?
我写了个简单的Rust程序,用HashMap<String, Vec<String>>实现需求——指定key不存在时插入新Vec,存在就往对应Vec里push元素。但像Code2那样把None分支的花括号去掉后就报类型不匹配错误,Code1保留花括号却能正常运行,想知道原因。
错误信息
error[E0308]: `match` arms have incompatible types --> src/main.rs:97:20 | 94 | / match get_option { 95 | | None => map.insert(str_check, vec![String::from("inserted!")]), | | ------------------------------------------------------ this is found to be of type `Option<Vec<String>>` 96 | | 97 | | Some(v) => v.push(String::from("Chris")), | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Option<Vec<String>>`, found `()` 98 | | } | |_____- `match` arms have incompatible types | = note: expected enum `Option<Vec<String>>` found unit type `()` note: method `push` modifies its receiver in-place --> src/main.rs:97:22 | 97 | Some(v) => v.push(String::from("Chris")), | ^^^^ this call modifies `v` in-place For more information about this error, try `rustc --explain E0308`.
Code1(正常运行)
use std::collections::HashMap; fn main() { let mut map: HashMap<String, Vec<String>> = HashMap::new(); map.insert(String::from("first"), Vec::new()); let str_check = String::from("second"); let get_option = map.get_mut(&str_check); match get_option { None => { map.insert(str_check, vec![String::from("inserted!")]); } Some(v) => v.push(String::from("Chris")), } println!("{:?}", map); }
Code2(报错)
use std::collections::HashMap; fn main() { let mut map: HashMap<String, Vec<String>> = HashMap::new(); map.insert(String::from("first"), Vec::new()); let str_check = String::from("second"); let get_option = map.get_mut(&str_check); match get_option { None => map.insert(str_check, vec![String::from("inserted!")]), Some(v) => v.push(String::from("Chris")), } println!("{:?}", map); }
原因解析
Rust的match表达式要求所有分支返回的类型必须完全一致,花括号在这里直接改变了分支的返回值类型:
带花括号的分支(Code1):
花括号包裹的是一个代码块,代码块的返回值由最后一行决定。如果最后一行是带分号的语句(比如Code1里的map.insert(...);),整个代码块会返回单元类型()。而Some分支里的v.push(...)方法本身返回的就是(),所以两个分支的返回类型都是(),符合match的要求,编译通过。去掉花括号的分支(Code2):
此时分支直接把map.insert(...)作为返回值,而HashMap::insert方法的返回类型是Option<Vec<String>>(key不存在时返回None,存在时返回旧值的Some)。但Some分支的v.push(...)返回的还是(),两个分支返回类型一个是Option<Vec<String>>,一个是(),类型不兼容,因此触发E0308类型不匹配错误。
如果想去掉花括号也正常运行,你可以把None分支的返回值强制转成(),比如用花括号包裹并加分号(直接保留花括号其实更清晰):
None => { map.insert(str_check, vec![String::from("inserted!")]); },
内容的提问来源于stack exchange,提问作者user125535
相关产品推荐
相关产品推荐

