Rust中match与unwrap_or在类型判定上的差异及报错原因咨询
这个问题挺典型的,咱们先对比两段代码的表现,再拆解背后的类型逻辑。
首先看这段能正常编译的代码(Rust 1.23.0版本):
fn main() { let r = String::from("a"); let a = Some(&r); let b = match a { Some(name) => name, None => "", }; println!("{}", b); }
而这段代码却编译失败:
fn main() { let r = String::from("a"); let a = Some(&r); let b = a.unwrap_or(""); println!("{}", b); }
编译器给出的报错信息是:
error[E0308]: mismatched types
--> src/main.rs:4:25
| 4 | let b = a.unwrap_or("");
| ^^ expected structstd::string::String, found str
核心原因:类型推导与方法签名的差异
咱们分别拆解两种场景:
1. match分支的类型统一逻辑
a的类型是Option<&String>,当执行match匹配时,Rust会尝试把两个分支的返回类型统一成同一个类型:
Some(name)分支返回的name是&String类型;None分支返回的""是&'static str类型。
因为String实现了Deref<Target=str> trait,Rust会自动对&String做Deref强制转换,把它转成&str。这样两个分支的返回类型就统一成了&str,b的类型也就被推导为&str,自然能正常编译。
2. unwrap_or的严格类型要求
unwrap_or是Option<T>上的方法,它的签名是:
fn unwrap_or(self, default: T) -> T
这个签名要求传入的default参数必须和Option内部的T类型完全一致。
这里a的类型是Option<&String>,所以T就是&String,那unwrap_or就要求我们传入的default也得是&String类型。但我们传的""是&'static str,这两个类型并不匹配,编译器自然会抛出类型不匹配的错误。
简单来说:match会自动做类型强制转换(包括Deref)来统一分支类型,而unwrap_or的方法签名是“硬要求”参数类型完全匹配,不会帮你自动做转换。
怎么修复unwrap_or的代码?
只需要把Option内部的类型转成&str就行,这样unwrap_or的参数""就和T类型匹配了:
fn main() { let r = String::from("a"); let a = Some(r.as_str()); // 显式把&String转成&str let b = a.unwrap_or(""); println!("{}", b); }
内容的提问来源于stack exchange,提问作者George

