[英]How can I convert a Result<T, E1> to Result<T, E2> when the question mark operator is ineffective?
当E2
为E1
实现了From
特征时Result<T, E2>
是否有一种惯用/简洁的方法将Result<T, E1>
转换为Result<T, E2>
?
我不能使用?
运算符,因为它不编译。
就我而言, E1
是ParseIntError
, E2
是自定义CalcPackageSizeError
错误枚举。
use std::error;
use std::fmt;
use std::io;
use std::io::Read;
use std::num::ParseIntError;
#[derive(Debug)]
enum CalcPackageSizeError {
InvalidInput(&'static str),
BadNum(&'static str),
}
impl error::Error for CalcPackageSizeError {}
impl fmt::Display for CalcPackageSizeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
Self::InvalidInput(err_desc) => err_desc,
Self::BadNum(err_desc) => err_desc,
}
)
}
}
impl From<ParseIntError> for CalcPackageSizeError {
fn from(_: ParseIntError) -> Self {
CalcPackageSizeError::BadNum(
"Error in calculating size of one or more of the packages involved.",
)
}
}
fn parse_comma_separated_num(num_str: &str) -> Result<usize, ParseIntError> {
num_str
.chars()
.filter(|char| *char != ',')
.collect::<String>()
.parse::<usize>()
}
fn calc_all_package_size(contents: &str) -> Result<usize, CalcPackageSizeError> {
contents
.split('\n')
.skip(2)
.map(|package_str| {
let amount_str = package_str
.split(' ')
.filter(|element| *element != "")
.nth(1);
if let Some(amt_str) = amount_str {
parse_comma_separated_num(amt_str)?
// match parse_comma_separated_num(amt_str) {
// Ok(amt) => Ok(amt),
// Err(err) => Err(From::from(err)),
// }
} else {
Err(CalcPackageSizeError::InvalidInput("Input not as expected, expected the 2nd spaces-delimited item to be the size (integer)."))
}
})
.sum()
}
fn main() {
let mut wajig_input = String::from(
"Package Size (KB) Status
=================================-==========-============
geoip-database 10,015 installed
aptitude-common 10,099 installed
ieee-data 10,137 installed
hplip-data 10,195 installed
librsvg2-2 10,412 installed
fonts-noto-color-emoji 10,610 installed",
);
// io::stdin().read_to_string(&mut wajig_input).expect("stdin io rarely fails.");
match calc_all_package_size(wajig_input.as_str()) {
Ok(total_size_in_kb) => {
let size_in_mb = total_size_in_kb as f64 / 1024.0;
println!("Total size of packages installed: {} MB", size_in_mb);
}
Err(error) => {
println!("Oops! Encountered some error while calculating packages' size.");
println!("Here's the error: \n {}", error);
println!("\n-- Gracefully exiting..");
}
}
}
这给出了编译错误:
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:59:17
|
52 | / if let Some(amt_str) = amount_str {
53 | | parse_comma_separated_num(amt_str)?
| | ----------------------------------- expected because of this
54 | | // match parse_comma_separated_num(amt_str) {
55 | | // Ok(amt) => Ok(amt),
... |
59 | | Err(CalcPackageSizeError::InvalidInput("Input not as expected, expected the 2nd spaces-delimited item to be the size (integer)."))
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found enum `Result`
60 | | }
| |_____________- `if` and `else` have incompatible types
|
= note: expected type `usize`
found enum `Result<_, CalcPackageSizeError>`
note: return type inferred to be `usize` here
--> src/main.rs:53:17
|
53 | parse_comma_separated_num(amt_str)?
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
虽然这两个错误在语义上看起来很相似,但我需要以不同的方式来应对这两种情况,所以我不能把它们放在一起。
使用Result::map_err
和Into::into
:
if let Some(amt_str) = amount_str {
parse_comma_separated_num(amt_str).map_err(Into::into)
} else {
Err(CalcPackageSizeError::InvalidInput("Input not as expected, expected the 2nd spaces-delimited item to be the size (integer)."))
}
正如Jmb 在评论中指出的那样,您还可以使用Ok
和?
一起:
if let Some(amt_str) = amount_str {
Ok(parse_comma_separated_num(amt_str)?)
} else {
Err(CalcPackageSizeError::InvalidInput("Input not as expected, expected the 2nd spaces-delimited item to be the size (integer)."))
}
问题是?
成功时解包值,失败时从函数返回。 这意味着parse_comma_separated_num(amt_str)?
计算结果为usize
,正如编译器告诉您的那样:
返回类型推断为
usize
这里
这将导致第一个块评估为usize
,第二个块评估为Result
。 这些不是同一类型,导致您得到错误。
使用map_err
转换错误类型map_err
值保留为Result
,从而允许两个块评估为相同的类型。
也可以看看:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.