在monad管道中使用into()

时间:2016-04-25 10:16:13

标签: types rust monads

我基本上试图在管道内转换一个值,如下所示:

#[derive(PartialEq)]
enum MyType { A, B }

impl Into<MyType> for i32 {
    fn into(self) -> MyType {
        match self {
            0 => MyType::A,
            _ => MyType::B
        }
    }
}

fn main() {
    let a: Result<i32, ()> = Ok(0);
    a.map(|int| int.into())
        .and_then(|enm| if enm == MyType::A { println!("A"); });
}

我遇到的问题是map()不知道应该输出哪种类型。

我尝试过的其他不起作用的事情:

a.map(|int| if int.into() as MyType == MyType::A { println!("A"); });

a.map(|int| int.into::<MyType>())
        .and_then(|enm| if enm == MyType::A { println!("A"); });

这确实有效,但感觉不必要的复杂:

a.map(|int| {
    let enm: MyType = int.into();
    if enm == MyType::A { println!("A"); }
});

有更好的方法吗?

2 个答案:

答案 0 :(得分:6)

您不应该实施Into,您应该实施From,这会自动为您提供Into impl。然后你可以打电话给a.map(MyType::from),一切正常:

impl From<i32> for MyType {
    fn from(i: i32) -> MyType {
        match i {
            0 => MyType::A,
            _ => MyType::B
        }
    }
}

fn main() {
    let a: Result<i32, ()> = Ok(0);
    a.map(MyType::from)
        .and_then(|enm| if enm == MyType::A { Err(()) } else { Ok(enm) } );
}

或者你可以拨打a.map(Into::<MyType>::into),但这相当冗长。 From / Into二元性是有原因的,std::convert module docs

中对此进行了解释

答案 1 :(得分:3)

  

我遇到的问题是map()不知道应该输出哪种类型。

那不是问题。

错误是:

<anon>:16:25: 16:63 error: mismatched types:
 expected `core::result::Result<_, ()>`,
    found `()`
(expected enum `core::result::Result`,
    found ()) [E0308]
<anon>:16         .and_then(|enm| if enm == MyType::A { println!("A"); });

那是因为Result::and_then的类型是

fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E>

因此它希望函数返回Result<U, E>。这意味着用于链接返回Result的函数并返回第一个遇到的错误,如果它遇到任何错误。

如果您只想要Ok(_)执行某些代码,则应使用if letmatch

fn main() {
    let a: Result<i32, ()> = Ok(0);
    if let Ok(MyType::A) = a.map(|int| int.into()) {
        println!("A");
    }
}

打印

A