Rust 能够用组合器简化代码编写。之前觉得没啥用,实际完成一个项目后,才知道组合器的威力强大。下面列举一下常见的组合器,可用于 Option、Result、集合等类型。
一、数值转换:数据类型不变,仅数值替换
1. or()
例子:
fn main() {
let x=Some(1);
let y = Some(2);
let z1 = x.or(y);
let z2 = None.or(y);
println!("{:?}", z1);
println!("{:?}", z2);
}
======== cargo run ========
Some(1)
Some(2)
组合器实现代码:
pub fn or(self, optb: Option<T>) -> Option<T> {
match self {
Some(_) => self,
None => optb,
}
}
2. and()
例子:
fn main() {
let x = Some(1);
let y = Some(2);
let z = x.and(y);
println!("{:?}", z);
}
======== cargo run ========
Some(2)
组合器实现代码:
pub fn and<U>(self, optb: Option<U>) -> Option<U> {
match self {
Some(_) => optb,
None => None,
}
}
3. or_else()
例子:
fn main() {
let x = Some(1);
let z = x.or_else(||Some(2));
println!("{:?}", z);
}
======== cargo run ========
Some(1)
组合器实现代码:
pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
match self {
Some(_) => self,
None => f(),
}
}
FnOnce
说明这个函数的参数是个闭包。
4. and_then()
例子:
fn main() {
let x = Some(1);
let z = x.and_then(|x| Some(x + 1));
println!("{:?}", z);
}
======== cargo run ========
Some(2)
组合器实现代码:
pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> {
match self {
Some(x) => f(x),
None => None,
}
}
FnOnce(T)
说明这个函数的参数是个闭包,而且以 T 为闭包函数的传入参数。
5. filter
例子:
fn main() {
let x = Some(3);
let x1 = x.filter(|x| x < &5);
let x2 = x.filter(|x| x > &5);
println!("x1 = {:?}", x1);
println!("x2 = {:?}", x2);
}
======== cargo run ========
x1 = Some(3)
x2 = None
组合器实现代码:
pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
if let Some(x) = self {
if predicate(&x) {
return Some(x);
}
}
None
}
话说 filter 也可用于数组,写了段代码如下:
fn main() {
let x = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let z = x.iter().filter(|x| **x < 5).collect::<Vec<_>>();
println!("z= {:?}", z);
}
======== cargo run ========
z= [1, 2, 3, 4]
组合器实现代码:
fn filter<P>(self, predicate: P) -> Filter<Self, P>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool,
{
Filter::new(self, predicate)
}
看代码,此 filter 非彼 filter。
二、类型转换:用新类型的数据替换原来的数据
1. map()
例子:
fn main() {
let x = Some("12345");
let z = x.map(|x| x.len());
println!("z = {:?}", z);
}
======== cargo run ========
z = Some(5)
组合器实现代码:
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
match self {
Some(x) => Some(f(x)),
None => None,
}
}
用于集合的例子。和上面的不是同一个map,后面所有的组合器实现代码都不贴了:
fn main() {
let x = vec![1, 2, 3, 4, 5];
let z = x.iter().map(|x| (*x) as f64).collect::<Vec<f64>>();
println!("z = {:?}", z);
}
======== cargo run ========
z = [1.0, 2.0, 3.0, 4.0, 5.0]
2. map_err()
只修改 Err 的值, Ok的值不变。看例子:
fn main() {
let x: Result<i32, i32> = Ok(123);
let y: Result<i32, i32> = Err(456);
let z1: Result<i32, i32> = x.map_err(|_| 999);
let z2: Result<i32, i32> = y.map_err(|_| 999);
println!("z1 = {:?}", z1);
println!("z2 = {:?}", z2);
}
======== cargo run ========
z1 = Ok(123)
z2 = Err(999)
3. map_or()
仅支持 Option
类型(不支持 Result
)。将闭包应用于 Some
中的值,然后根据闭包返回输出。对于 None
将返回给定的默认值。
fn main() {
let x: Option<i32> = Some(123);
let y: Option<i32> = None;
let z1 = x.map_or(999, |x| x * 2);
let z2 = y.map_or(999, |x| x * 2);
println!("z1 = {:?}", z1);
println!("z2 = {:?}", z2);
}
======== cargo run ========
z1 = 246
z2 = 999
4. map_or_else()
支持 Option
类型和 Results
类型(Result
还在 nightly)。与 map_or()
类似,但要对于第一个参数,要提供另一个闭包,而不是默认值。
fn main() {
let x: Option<i32> = Some(123);
let y: Option<i32> = None;
let z1 = x.map_or_else(|| 999, |x| x * 2);
let z2 = y.map_or_else(|| 999, |x| x * 2);
println!("z1 = {:?}", z1);
println!("z2 = {:?}", z2);
}
======== cargo run ========
z1 = 246
z2 = 999
5. ok_or() : Option -> Result
ok_or()
将Option类型转换为Result类型。
例子:
fn main() {
let x = Some(123);
let y: Option<i32> = None;
let z1: Result<i32, i32> = x.ok_or(999);
let z2: Result<i32, i32> = y.ok_or(999);
println!("z1 = {:?}", z1);
println!("z2 = {:?}", z2);
}
======== cargo run ========
z1 = Ok(123)
z2 = Err(999)
6. ok_or_else() : Option -> Result
ok_or_else()
将Option类型转换为Result类型,用闭包作为参数。
fn main() {
let x = Some(123);
let y: Option<i32> = None;
let z1: Result<i32, i32> = x.ok_or_else(||999);
let z2: Result<i32, i32> = y.ok_or_else(||999);
println!("z1 = {:?}", z1);
println!("z2 = {:?}", z2);
}
======== cargo run ========
z1 = Ok(123)
z2 = Err(999)
三、变量形态变化
1. as_ref():Some(T) -> Some(&T), Result<S,T> -> Result<&S,&T>
例子(Option):
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
fn main() {
let mut x= Some(123);
print_type_of(&x);
let z = x.as_ref();
print_type_of(&z);
}
======== cargo run ========
core::option::Option<i32>
core::option::Option<&i32>
例子(Result):
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
fn main() {
let mut x:Result<i32,i32>= Ok(123);
print_type_of(&x);
let z = x.as_ref();
print_type_of(&z);
}
======== cargo run ========
core::result::Result<i32, i32>
core::result::Result<&i32, &i32>
2. as_mut():Option(T) -> Option(&mut T), Result<S,T> -> Result<&mut S,&mut T>
例子(Option):
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
fn main() {
let mut x= Some(123);
print_type_of(&x);
let z = x.as_mut();
print_type_of(&z);
}
======== cargo run ========
core::option::Option<i32>
core::option::Option<&mut i32>
例子(Result):
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
fn main() {
let mut x:Result<i32,i32>= Ok(123);
print_type_of(&x);
let z = x.as_mut();
print_type_of(&z);
}
======== cargo run ========
core::result::Result<i32, i32>
core::result::Result<&mut i32, &mut i32>