Rust 匹配结果类型时提前退出

Rust 匹配结果类型时提前退出,rust,Rust,我有一个参数类型为Result的方法。我非常喜欢链接,所以我在参数上使用和_-then。在某个时候,我想有条件地从和_-then内部返回整个方法(因此有可能调用另一个和_-then方法): 我希望有办法让它编译。我可以分解这个方法,去掉和_then,但可能有一种方法可以使用和_then 在我的真实代码中,我有更多的和_-then,它们将类型映射到其他类型、错误映射等,因此这是我所面临问题的简化再现路径 这是从我的代码库复制粘贴的代码,显示多个和_然后。我正在将外部库中的错误映射到我自己的错误类型

我有一个参数类型为
Result
的方法。我非常喜欢链接,所以我在参数上使用
和_-then
。在某个时候,我想有条件地从
和_-then
内部返回整个方法(因此有可能调用另一个
和_-then
方法):

我希望有办法让它编译。我可以分解这个方法,去掉
和_then
,但可能有一种方法可以使用
和_then

在我的真实代码中,我有更多的
和_-then
,它们将类型映射到其他类型、错误映射等,因此这是我所面临问题的简化再现路径

这是从我的代码库复制粘贴的代码,显示多个
和_然后
。我正在将外部库中的错误映射到我自己的错误类型中,因此如果存在错误,可以自动返回错误。我想不断更改我从
和_然后
获得的类型,以便最终获得类型
用户
(尽管它目前不起作用)。一个选项是不链接块并创建单独的值,但我希望可以在闭包中直接将值返回给调用方

db_session
    .query_with_values(query, values)
    .map_err(|e| {
        error!("{:?}", e);
        TechnicalServerError::SERVER_RETRY
    })
    .and_then(|f| {
        f.get_body().map_err(|e| {
            error!("{:?}", e);
            TechnicalServerError::SERVER_RETRY
        })
    })
    .and_then(|b| b.into_rows().ok_or(TechnicalServerError::SERVER_RETRY))
    .and_then(|mut c| {
        if let Some(row) = c.pop() {
            User::try_from_row(row).map_err(|e| {
                error!("{:?}", e);
                TechnicalServerError::SERVER_INVALID
            })
        } else {
            return Ok(Login::Other(LoginResult::UNKNOWN_USER));
        }
    })
    .and_then(|u| {
        // 'u' should be of type 'user' at this point
        // some user code here...
    })

不是干净的。不如改成

fn s(r: Result<Good, ()>) -> Result<Food, ()> {
    let p = match r? {
        // Should be called in the next and_then block
        Good::Ok => Pizza::Tomato,
        // Should be called in the next and_then block
        Good::Good => Pizza::Pineapple,
        Good::VeryGood => {
            return Ok(Food::Burger(Burger::Cow));
        },
    };

    Ok(Food::Pizza(p))
}
fns(r:Result)->Result{
让p=匹配r{
//应在下一个和_然后块中调用
好的::好的=>比萨饼::西红柿,
//应在下一个和_然后块中调用
好的::好的=>比萨饼::菠萝,
好的::VeryGood=>{
返回Ok(食物:汉堡(汉堡:牛));
},
};
Ok(食物:比萨饼(p))
}

查看您编辑的示例,我创建了一个:

/。。。
,然后(|b | b.进入_行().ok_或(TechnicalServerError::SERVER_RETRY))
.然后| mut c |{
如果让一些(行)=c.pop(){
用户::try_from_row(row).map_err(| e |{
错误!(“{:?}”,e);
TechnicalServerError::服务器\u无效
})
}否则{
返回Ok(登录::其他(登录结果::未知用户))
}
}).然后| u |{
//此时,“u”应为“用户”类型
//这里有一些用户代码。。。
我认为人们对
和_then
的作用有一个基本的误解

  • 和_然后
    获取一个
    结果
    ,以及一个将
    T
    转换为
    结果
    (即
    FnOnce(T)->结果
    )的函数。当您想要同时操作
    Ok(val)
    错误
    时,可以使用该函数,例如,您想要更改重新映射错误并进行一些值处理

  • map
    获取一个
    结果
    和一个将
    T
    转换为另一个值
    U
    (即
    FnOnce(T)->U
    )的函数。当您想要更改
    Ok(val)
    而不影响
    错误
    部分时,请使用此函数

您说要更改用户,可能是这样的:

db\u会话
.使用_值查询_(true)
.map|u err(| e|{
println!(“{:?}”,e);
MyError::服务器重试
})
。然后(| f | f.get_body(true)。映射错误(| e2|{
println!(“{:?}”,e2);
MyError::服务器重试
}))
.和|然后(| b | b.进入|行(true)。确定_或(MyError::ServerRetry))
.然后| mut c|{
如果让一些(行)=c.pop(){
用户::from_row(row).map_err(| e3 |{
println!(“{:?}”,e3);
MyError::服务器重试
})
}否则{
返回Ok(用户{name:“X.”to_string()})
}
})
.map(|多用户|{
user.name=“CHANGED.”to_string();
用户
});


但是,正如您所看到的,查询的值始终是
Result
,直接对该值进行操作的唯一方法是
unwrap
,但如果遇到错误,它会崩溃。或者,您可以使用
if let
来获得值,而不会崩溃。

这在我提供的代码中确实有效:)然而,在我的“真实”代码中,我有更多的and_,它们映射类型和错误,遗憾的是,这种方式是不够的:(无论如何,谢谢你的回答,我会更新我的问题,使其更详细。)clear@J.Doe:那么,你能创建一个更真实的示例/显示真实的代码吗?你不能像那样使用
返回
,因此任何替代方案都可能需要更多的上下文。(另外,这是针对稳定的锈迹还是
#![feature]
s可以吗?)简单地说,我正在链接多个and_then's,有时,我只想说(在and_then块中):好的,如果某个值为真,只需将该值返回给调用者,否则只需调用next和_then。这是稳定的。总而言之:and then块中的return语句实际上不会返回函数,而是将给定类型映射到返回值,使其在next和_then块中可用?@J.Doe:
return
returns fr对于作为参数传递给
和_then
,是的。@J.Doe您能将示例更改为具有多个
和_then
?您发布的代码没有编译。您能编辑它以更好地向我们展示工作流吗?另外,您为什么要提前返回?有具体原因吗?对我来说,使用
用一个返回点映射
。@DanielFath请参阅我的编辑。您的问题似乎可以用的答案来回答。如果没有,请您的问题解释差异。否则,我们可以将此问题标记为已回答。您还应该阅读,其中讨论了如何使
自动包装基本错误。
fn s(r: Result<Good, ()>) -> Result<Food, ()> {
    let p = match r? {
        // Should be called in the next and_then block
        Good::Ok => Pizza::Tomato,
        // Should be called in the next and_then block
        Good::Good => Pizza::Pineapple,
        Good::VeryGood => {
            return Ok(Food::Burger(Burger::Cow));
        },
    };

    Ok(Food::Pizza(p))
}