我正在开发一个将 json 值转换为
i32
的函数,如果转换的任何步骤失败,则返回错误。
fn json_to_block_height(height: Value) -> Result<i32, RPCError> {
let err_msg = "Invalid height".to_string();
let height = match height {
Value::Number(h) => Ok(h),
_ => Err(RPCError::CustomError(1, err_msg.clone())),
}?;
let height = height
.as_i64()
.ok_or(RPCError::CustomError(1, err_msg.clone()))?;
if height < 0 {
return Err(RPCError::CustomError(1, err_msg));
}
i32::try_from(height).map_err(|_| RPCError::CustomError(1, err_msg))
}
是否有任何好方法可以防止在
match
分支和 ok_or
参数中不必要地克隆错误消息,而无需使用显式 if...else...
分支展开整个代码?从技术上讲,如果满足任何这些错误条件,则以下代码将无法访问,因此我们永远不需要在完美的世界中移动此字符串。
我尝试用
ok_or(RPCError::CustomError(1, err_msg.clone())
替换 ok_or_else(|| RPCError::CustomError(1, err_msg.clone())
方法,但 err_msg 似乎仍然被捕获并在闭包中移动。
额外问题:通过使用显式分支使代码更加冗长以避免不必要的复制,是否会提高性能,或者尽管存在这些副本,“惯用的 rust”解决方案是否性能更高?
可以像这样删除显式克隆,尽管我不认为这会对性能产生任何影响:
#![allow(dead_code)]
enum RPCError {
CustomError(usize, String),
}
use serde_json::Value; // 1.0.133
fn json_to_block_height(height: Value) -> Result<i32, RPCError> {
let err_msg = "Invalid height".to_string();
let height = match height {
Value::Number(h) => h,
_ => return Err(RPCError::CustomError(1, err_msg)),
};
let height = match height.as_i64() {
Some(h) => h,
None => return Err(RPCError::CustomError(1, err_msg)),
};
if height < 0 {
return Err(RPCError::CustomError(1, err_msg));
}
i32::try_from(height).map_err(|_| RPCError::CustomError(1, err_msg))
}
或更实用的:
#![allow(dead_code)]
enum RPCError {
CustomError(usize, String),
}
use serde_json::Value; // 1.0.133
fn json_to_block_height(height: Value) -> Result<i32, RPCError> {
let err_msg = "Invalid height".to_string();
match height {
Value::Number(h) => match h.as_i64() {
Some(h) if h >= 0 => i32::try_from(h).map_err(|_| RPCError::CustomError(1, err_msg)),
_ => Err(RPCError::CustomError(1, err_msg)),
},
_ => Err(RPCError::CustomError(1, err_msg)),
}
}