Rust组合器

Combinators are methods that ease the manipulation of some type T . They favor a functional (method chaining) style of code.
                                                                        -- 《Black Hat Rust》 Sylvain Kerkour

组合器是 简化 对某些类型T的操作的方法。它提倡以函数式(方法链)风格编写代码。

本文列举一下常见的组合器,可用于 OptionResult 等类型。

Option 常用 Combinators

or

如果 Option 的值不为 None ,则直接返回此 Option ,如果 Option 的值是 None ,则返回 or 函数的参数 ( Option 类型)。

fn main() {
    let port: Option<String> = std::env::var("PORT").ok();
    let port = port.or(Some(String::from("8080")));
    println!("{}", port.unwrap());
}

// 输出
// 8080

or_else

与 or 类似,只是参数是一个返回 Option 类型的闭包

fn main() {
    let port: Option<String> = std::env::var("PORT").ok();
    let port = port.or_else(|| Some(String::from("8080")));
    println!("{}", port.unwrap());
}

// 输出
// 8080

and 和 and_then

如果调用 and 或者 and_then 的值为 None 则直接返回 None,否则返回参数中的内容,区别在于 and 的参数是 Option 类型的值,and_then 函数的参数是一个闭包,接收 Option 包裹的类型,并返回一个 Option

fn main() {
    let a: Option<String> = Some(String::from("8080"));
    let b: Option<String> = Some(String::from("9090"));
    let c: Option<String> = a.and(b);

    let x: Option<String> = None;
    let y: Option<String> = Some(String::from("8080"));

    let z = y.and(x);

    println!("{:?} , {:?}", c, z);
}

// 输出
// Some("9090") , None

fn main() {
    let a: Option<String> = Some(String::from("8080"));
    let b: Option<String> = a.and_then(|v| Some(String::from(format!("127.0.0.1:{}", v))));

    let x: Option<String> = None;
    let z = x.and_then(|v| Some(v));

    println!("{:?} , {:?}", b, z);
}

// 输出
// Some("127.0.0.1:8080") , None

filter

filter 使用闭包参数对 Option 包裹的数据进行过滤,如果闭包调用返回 false 则整个函数返回 None

fn main() {
    let port: Option<String> = std::env::var("PORT").ok();
    let l = port.filter(|x| x.len() >= 3);

    println!("{:?}", l);
}


// 输出
// $ ./target/debug/testing
// None
// $ export PORT=90
// $ ./target/debug/testing
// None
// $ export PORT=9090      
// $ ./target/debug/testing
// Some("9090")

map

如果 Option 不为 None,则使用参数的闭包函数转换 Option 包裹的类型

fn main() {
    let port: Option<String> = std::env::var("PORT").ok();
    let x = port.map(|v| v.parse::<i32>().unwrap());
    println!("{:?}", x);
}

// 输出
// $ ./target/debug/testing
// None
// $ export PORT=9090
// $ ./target/debug/testing
// Some(9090)
// $ unset PORT

map_or

如果 Option 为 None ,则使用默认值,否则,调用闭包转换 Option 包裹的值

fn main() {
    let port: Option<String> = std::env::var("PORT").ok();
    let x = port.map_or(String::from("127.0.0.1:8080"), |v| {
        format!("127.0.0.1:{}", v)
    });
    println!("{:?}", x);
}

// 输出
// $ ./target/debug/testing
// "127.0.0.1:8080"
// $ export PORT=9090      
// $ ./target/debug/testing
// "127.0.0.1:9090"
// $ unset PORT            

map_or_else

map_or_else 在 Option 为 None 时,调用第一个闭包参数,生成默认值,在 Option 不为 None 时,调用第二个闭包参数对 Some 包裹的数据进行转换

fn main() {
    let port: Option<String> = std::env::var("PORT").ok();
    let x = port.map_or_else(
        || String::from("127.0.0.1:8080"),
        |v| format!("127.0.0.1:{}", v),
    );
    println!("{:?}", x);
}

// 输出
// $ ./target/debug/testing
// "127.0.0.1:8080"
// $ export PORT=9090
// $ ./target/debug/testing
// "127.0.0.1:9090"
// $ unset PORT

其它方法

unwrap_or

获取 Option 包裹的值,如果 Option 的值是 None ,则返回 unwrap_or 函数的参数。

fn main() {
    let port:Option<String> =std::env::var("PORT").ok();
    let port = port.unwrap_or(String::from("8080"));
    println!("{}", port);
}

// 输出
// 8080

is_some 和 is_none

fn main() {
    let a: Option<u32> = Some(1);
    let b: Option<u32> = None;
    println!("a : {} {} ", a.is_some(), a.is_none());
    println!("b : {} {} ", b.is_some(), b.is_none());
}

// 输出
// a : true false 
// b : false true 

Result 常用 Combinators

ok

将 Result 转换成 Option

fn main() {
    let x: Result<String, String> = Ok("8080".to_string());
    let y: Result<String, String> = Err("No".to_string());

    println!("{:?} {:?}", x.ok(), y.ok())
}

// 输出
// Some("8080") None

or

与 Option 的 or 类似

fn main() {
    let port: Result<String, std::env::VarError> = std::env::var("PORT");
    let port: Result<String, std::env::VarError> = port.or(Ok(String::from("8080")));
    println!("{}", port.unwrap());
}

// 输出
// 8080

or_else

与 Option 的 or_else 类似,区别在于传入参数的闭包接收一个 Error ,在闭包中处理 Error 并返回新的 Result。

fn main() {
    let port: Result<String, std::env::VarError> = std::env::var("PORT");
    let port: Result<String, std::env::VarError> = port.or_else(|x| {
        println!("{}", x);
        Ok(String::from("8080"))
    });
    println!("{}", port.unwrap());
}

// 输出
// environment variable not found
// 8080

and

与 Option 的 and 函数类似

fn main() {
    let port: Result<String, std::env::VarError> = std::env::var("PORT");
    let port: Result<String, std::env::VarError> = port.and(Ok(String::from("9090")));
    println!("{:?}", port);
}


// 输出 
// $ ./target/debug/testing
// Err(NotPresent)
// $ export PORT=9090
// $ ./target/debug/testing
// Ok("9090")
// $ unset PORT

and_then

与 Option 的 and_then 函数类似,区别在于传入参数的闭包接收一个Result包裹的类型参数 ,在闭包中可以使用此值来生成新的 Result 值。

fn main() {
    let port: Result<String, std::env::VarError> = std::env::var("PORT");
    let port: Result<String, std::env::VarError> = port.and_then(|x| {
        println!("{}", x);
        Ok(String::from("8080"))
    });
    println!("{:?}", port);
}

// 输出
// $ ./target/debug/testing
// Err(NotPresent)
// $ export PORT=9090
// $ ./target/debug/testing
// 9090
// Ok("8080")
// $ unset PORT 

map

与 Option 的 map 类似

fn main() {
    let port: Result<String,std::env::VarError> = std::env::var("PORT");
    let x = port.map(|v| v.parse::<i32>().unwrap());
    println!("{:?}", x);
}

// 输出
// $ ./target/debug/testing
// Err(NotPresent)
// $ export PORT=9090
// $ ./target/debug/testing
// Ok(9090)
// $ unset PORT

map_err

当 Result 的值为 Err 时,使用此函数的闭包参数,将 Err 转换,生成另一个 Err

fn main() {
    let port: Result<String, std::env::VarError> = std::env::var("PORT");
    let x = port.map_err(|v| {
        println!("{}", v);
        "no found"
    });
    println!("{:?}", x);
}


// 输出
// $ ./target/debug/testing
// environment variable not found
// Err("no found")
// $ export PORT=9090      
// $ ./target/debug/testing
// Ok("9090")
// $ unset PORT

map_or

如果 Result 为 Err ,则使用默认值,否则,调用闭包转换 Result 包裹的值

fn main() {
    let port: Result<String, std::env::VarError> = std::env::var("PORT");
    let x = port.map_or(String::from("127.0.0.1:8080"), |v| {
        format!("127.0.0.1:{}", v)
    });
    println!("{:?}", x);
}

// 输出
// $ ./target/debug/testing
// "127.0.0.1:8080"
// $ export PORT=9090      
// $ ./target/debug/testing
// "127.0.0.1:9090"
// $ unset PORT            

map_or_else

map_or_else 在 Result 为 Err 时,调用第一个闭包参数处理异常,并生成默认值,在 Result 为 Ok 时,调用第二个闭包,转换 Ok 包裹的数据

fn main() {
    let port: Result<String, std::env::VarError> = std::env::var("PORT");
    let x = port.map_or_else(
        |err| {
            println!("{}", err);
            String::from("127.0.0.1:8080")
        },
        |v| format!("127.0.0.1:{}", v),
    );
    println!("{:?}", x);
}

// 输出
// $ ./target/debug/testing
// environment variable not found
// "127.0.0.1:8080"
// $ export PORT=9090      
// $ ./target/debug/testing
// "127.0.0.1:9090"
// $ unset PORT            

参考资料

Combinators