Error handling Rust中的合成错误:Ok上的浓缩结果

Error handling Rust中的合成错误:Ok上的浓缩结果,error-handling,rust,Error Handling,Rust,我有以下代码。它起作用了 但我更感兴趣的是编写泡茶,其中我调用了两个函数:从奶牛那里获取牛奶和倒牛奶。它们都返回结果 如何编写它们,以便在它们成功的情况下继续浓缩Strings,否则返回错误 enum TeaError { NoMilk, NoCup, NoCow, NoGas, NoSomething, } fn get_milk_from_cow(cow: bool) -> Result<String, TeaError> {

我有以下代码。它起作用了

但我更感兴趣的是编写
泡茶
,其中我调用了两个函数:
从奶牛那里获取牛奶
倒牛奶
。它们都返回
结果

如何编写它们,以便在它们成功的情况下继续浓缩
String
s,否则返回错误

enum TeaError {
    NoMilk,
    NoCup,
    NoCow,
    NoGas,
    NoSomething,
}

fn get_milk_from_cow(cow: bool) -> Result<String, TeaError> {
    if cow {
        Ok(String::from("get milk from cow"))
    } else {
        Err(TeaError::NoCow)
    }
}

fn pour_milk(milk: bool) -> Result<String, TeaError> {
    if milk {
        Ok(String::from("poured milk"))
    } else {
        Err(TeaError::NoMilk)
    }
}

fn make_tea() -> Result<String, TeaError> {
    let mut process = String::new();
    let step_cow = get_milk_from_cow(true)?;
    let step_milk = pour_milk(true)?;
    process.push_str(step_cow.as_str());
    process.push_str(step_milk.as_str());
    Ok(process)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn attemp_tea_one() {
        match pour_milk(false) {
            Err(v) => match v {
                TeaError::NoMilk => assert!(true),
                _ => assert!(false)
            },
            Ok(_) => assert!(false)
        };
    }

    #[test]
    fn attemp_tea_two() {
        match make_tea() {
            Err(_) => assert!(false),
            Ok(_) => assert!(true)
        };
    }
}
但它给出了:

错误[E0308]:类型不匹配
-->src/errors.rs:27:22
|
27 |过程。推动(从奶牛身上获取牛奶(正确)?推动(倾倒牛奶(正确)?作为牛奶();
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
=注意:应为类型“%str”`
找到类型“%1”()`
as
push\u str
不返回字符串

编辑:

fn append(s1: String, s2: String) -> String {
    s1 + s2.as_str()
}
fn make_tea() -> Result<String, TeaError> {
    let process = append(get_milk_from_cow(true)?,
                         pour_milk(true)?);
    Ok(process)
}
fn追加(s1:String,s2:String)->String{
s1+s2.as_str()
}
fn泡茶()->结果{
let process=append(从奶牛身上获取牛奶)(真)?,
倒牛奶(真的);
Ok(流程)
}
所以,我可以做
append(append(funcA(),funcB()),funcC())
等等。。
我仍在学习生命周期,并思考是否仍然可以改进内存分配。

第一件事:上面的代码似乎没有什么问题,但我假设您正在寻找更地道的代码

虽然比您的方法需要稍多的内存,但是连接字符串结果的最优雅的方法是:

fn make_tea() -> Result<String, TeaError> {
    vec![get_milk_from_cow(true), pour_milk(true)].into_iter()
        .collect()
}


必须创建向量,因为数组不提供所属元素的迭代器(
&T
而不是
T
)。但是,我们可以通过一个额外的映射来解决这个问题:

fn make_tea() -> Result<String, TeaError> {
    Ok([get_milk_from_cow(true)?, pour_milk(true)?].into_iter()
        .map(|a| a.as_str())
        .collect())
}
fn泡茶()->结果{
好的([从母牛那里得到牛奶(真的)?,把牛奶(真的)?)倒进冰箱()
.map(|a | a.as_str())
.collect())
}

这将把
&String
中的元素映射到
&str
,同样可以收集到这些元素。

第一件事:上面的代码似乎没有什么问题,但我假设您正在寻找更地道的东西

虽然比您的方法需要稍多的内存,但是连接字符串结果的最优雅的方法是:

fn make_tea() -> Result<String, TeaError> {
    vec![get_milk_from_cow(true), pour_milk(true)].into_iter()
        .collect()
}


必须创建向量,因为数组不提供所属元素的迭代器(
&T
而不是
T
)。但是,我们可以通过一个额外的映射来解决这个问题:

fn make_tea() -> Result<String, TeaError> {
    Ok([get_milk_from_cow(true)?, pour_milk(true)?].into_iter()
        .map(|a| a.as_str())
        .collect())
}
fn泡茶()->结果{
好的([从母牛那里得到牛奶(真的)?,把牛奶(真的)?)倒进冰箱()
.map(|a | a.as_str())
.collect())
}

这将把
&String
中的元素映射到
&str
,可以同样地收集这些元素。

此代码在带星号的行上执行冗余工作:

fn make_tea() -> Result<String, TeaError> {
*   let mut process = String::new();
    let step_cow = get_milk_from_cow(true)?;
    let step_milk = pour_milk(true)?;
*   process.push_str(step_cow.as_str());
    process.push_str(step_milk.as_str());
    Ok(process)
}
或者更方便地说

fn make_tea() -> Result<String, TeaError> {
    Ok(get_milk_from_cow(true)? + &pour_milk(true)?)
}
fn泡茶()->结果{
好的(从奶牛身上取牛奶(正确)?+&倒牛奶(正确)?)
}

此代码在星号行上执行冗余工作:

fn make_tea() -> Result<String, TeaError> {
*   let mut process = String::new();
    let step_cow = get_milk_from_cow(true)?;
    let step_milk = pour_milk(true)?;
*   process.push_str(step_cow.as_str());
    process.push_str(step_milk.as_str());
    Ok(process)
}
或者更方便地说

fn make_tea() -> Result<String, TeaError> {
    Ok(get_milk_from_cow(true)? + &pour_milk(true)?)
}
fn泡茶()->结果{
好的(从奶牛身上取牛奶(正确)?+&倒牛奶(正确)?)
}

如果图片中没有
结果
,也就是说,如果
从奶牛那里得到牛奶
倒牛奶
返回
字符串
s,你会怎么做?@user4815162342
倒牛奶
是任何可能失败的功能的象征。我的观点是,问题不在于这些功能失败(由
操作符负责),但是在
推送str
返回
()
中,请告诉我们当
结果不存在时,您将如何连接字符串,以便更好地理解您希望通过
结果
@user4815162342实现什么。谢谢您的问题,我想我已经找到了(可能效率低下)解决方案,思考你的问题。如果图片中没有
结果
,也就是说,如果
从奶牛那里得到牛奶
倒牛奶
返回
字符串
s,你会怎么做?@user4815162342
倒牛奶
是任何可能失败的函数的象征。我的观点是,问题不在于那些函数失败(由
操作符负责),但是在
推送str
返回
()
中,请告诉我们当
结果不存在时,您将如何连接字符串,以便更好地理解您希望通过
结果
@user4815162342实现什么。谢谢您的问题,我想我已经找到了(可能效率低下)解决方案,思考您的问题..但在我的代码中,第一个错误一旦发生就会传播。即,不再需要进一步的电话来泡茶。即,如果
从奶牛那里获取牛奶
失败
倾倒牛奶
将不会被调用。我认为这就是
的目的。我认为这不是vec解决方案中会发生的情况。AshishNegi是正确的。你应该考虑改进你的问题以避免进一步的混淆。你最好使用<代码> [GETZYMKYROFRONSFOW(TRUE)?& PulyCalm(True)]?
,因为它比较短并且是预先分配的。@Veedrac似乎是由不稳定的trait
SliceConcatExt
提供的,我不想使用它。@E_net4,从2015年8月开始。但是在我的代码中,第一个错误一发生就传播开来。也就是说,泡茶就不再需要更多的电话了。也就是说,如果
从奶牛那里得到牛奶
失败<代码> PuluS奶将不被调用。我认为这是<代码> >代码>。我认为这不是在你的VEC解决方案中会发生的。@ AshishNegi是真的。你应该考虑改进你的问题以避免进一步的混淆。你最好使用<代码> [& GETYMIKYROFROXYBOY(TRUE)?& PulyMalk(真)?]
,因为它较短且预先分配。@Veedrac似乎是由不稳定的trait
SliceConcatExt
提供的,我不想使用它。@E_net4,自2015年8月起。