如何不在匹配分支或 ok_or 参数中捕获或移动字符串

问题描述 投票:0回答:1

我正在开发一个将 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”解决方案是否性能更高?

rust move-semantics
1个回答
0
投票

可以像这样删除显式克隆,尽管我不认为这会对性能产生任何影响:

#![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)),
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.