< 返回版块

kaoet 发表于 2020-09-28 15:10

假设有

let a = Some(1);
let b = Some(2);
let f = |(x, y)| x + y;

不知道标准库里有没有一个简便的方法实现如下功能:

let c = match a {
  None => b,
  Some(a_value) => match b {
    None => Some(a_value),
    Some(b_value) => Some(f(a_value, b_value)),
  }
};

评论区

写评论
zydxhs 2020-10-07 22:16

这个是否可行?

    let a = Some(1);
    let b = Some(2);
    let f = match (a, b) {
        (Some(a), Some(b)) => Some(f(a, b)),
        (Some(a), None) => Some(a),
        (None, Some(b)) => Some(b),
        _ => None,
    };
songzhi 2020-09-29 10:52

a.map(|a| b.map_or(a, |b| a + b)).or(b); 感觉可读性很差

whfuyn 2020-09-28 20:28
fn f<T>(a: Option<T>, b: Option<T>, g: fn(T, T) -> T) -> Option<T> {
    match (a, b) {
        (Some(a), Some(b)) => Some(g(a, b)),
        (a, b) => a.or(b),
    }
}

fn main() {
    let g = |a, b| a + b;
    assert_eq!(f(None, None, g), None);
    assert_eq!(f(Some(1), None, g), Some(1));
    assert_eq!(f(None, Some(2), g), Some(2));
    assert_eq!(f(Some(3), Some(4), g), Some(7));
    println!("ok");
}

感觉好不到哪里去

Dengjianping 2020-09-28 19:56
let c = a.zip(b).map(|(x, y)| x + y).or(a).or(b);

--
👇
xiaopengli89: a 或 b 为 None 时结果不是预期的。

--
👇
Dengjianping: ```rust let c = a.zip(b).map(|(x, y)| x + y);


xiaopengli89 2020-09-28 18:49

a 或 b 为 None 时结果不是预期的。

--
👇
Dengjianping: ```rust let c = a.zip(b).map(|(x, y)| x + y);

Dengjianping 2020-09-28 18:42
let c = a.zip(b).map(|(x, y)| x + y);
xiaopengli89 2020-09-28 18:16

修正下,返回值是Option

let a = Some(1);
let b = None;
let sum = a.iter().chain(b.iter()).fold(None, |acc, x| if let Some(acc) = acc {
    Some(acc + *x)
} else {
    Some(*x)
});
sum

Some(1)

xiaopengli89 2020-09-28 18:08

Option -> Iter -> Chain

let a = Some(1);
let b = Some(2);
let sum = a.iter().chain(b.iter()).fold(0, |acc, x| acc + *x);
sum

3

let a = Some(1);
let b = None;
let sum = a.iter().chain(b.iter()).fold(0, |acc, x| acc + *x);
sum

1

laizy 2020-09-28 17:23
let c = match (a, b) {
 (Some(a), Some(b)) => Some(f(a, b)),
 (None, b) => b,
 (a, None) => a,
 };
 
cnwzhjs 2020-09-28 16:03

这么写可能更加符合你的需求

trait OptionEitherZipWith<T, F>
    where F: FnOnce(T, T) -> T
{
    fn either_zip_with(self, other: Option<T>, f: F) -> Option<T>;
}

impl<T, F> OptionEitherZipWith<T, F> for Option<T>
    where F: FnOnce(T, T) -> T
{
    fn either_zip_with(self, other: Option<T>, f: F) -> Option<T>  {
        match (self, other) {
            (Some(a), Some(b)) => Some(f(a, b)),
            (Some(a), None) => Some(a),
            (None, Some(b)) => Some(b),
            _ => None
        }
    }
}

fn main()
{
    let a = Some(1);
    let b = Some(2);
    let c = a.either_zip_with(b, |a, b| { a + b });
    println!("hello, {:?}", c);
}

--
👇
kaoet: 没错,对于整数可以这样写。但实际情况是,我拥有的是Option<Strange>。这个Strange类型是可以做加法的,但没有加法单位元(也就是0)。所以.unwrap_or(0)这种方式不太好使……

--
👇
cnwzhjs: sorry, 没仔细看 这个需求似乎比较奇怪,可能只能这么写:

let a = Some(1);
let b = Some(2);
let c = match (a, b) {
    (None, None) => None,
    (a, b) => Some(a.unwrap_or(0) + b.unwrap_or(0))
};
uno 2020-09-28 15:52

使用unwrap_or_default()

--
👇
kaoet: 没错,对于整数可以这样写。但实际情况是,我拥有的是Option<Strange>。这个Strange类型是可以做加法的,但没有加法单位元(也就是0)。所以.unwrap_or(0)这种方式不太好使……

--
👇
cnwzhjs: sorry, 没仔细看 这个需求似乎比较奇怪,可能只能这么写:

let a = Some(1);
let b = Some(2);
let c = match (a, b) {
    (None, None) => None,
    (a, b) => Some(a.unwrap_or(0) + b.unwrap_or(0))
};
作者 kaoet 2020-09-28 15:51

没错,对于整数可以这样写。但实际情况是,我拥有的是Option<Strange>。这个Strange类型是可以做加法的,但没有加法单位元(也就是0)。所以.unwrap_or(0)这种方式不太好使……

--
👇
cnwzhjs: sorry, 没仔细看 这个需求似乎比较奇怪,可能只能这么写:

let a = Some(1);
let b = Some(2);
let c = match (a, b) {
    (None, None) => None,
    (a, b) => Some(a.unwrap_or(0) + b.unwrap_or(0))
};
cnwzhjs 2020-09-28 15:46

sorry, 没仔细看 这个需求似乎比较奇怪,可能只能这么写:

let a = Some(1);
let b = Some(2);
let c = match (a, b) {
    (None, None) => None,
    (a, b) => Some(a.unwrap_or(0) + b.unwrap_or(0))
};

--
👇
kaoet: 代码不等价。 我的例子里,merge(Some(1), None) = Some(1),你的代码中merge(Some(1), None) = None.

--
👇
cnwzhjs: 也可以用lambda:

fn main()
{
    let a = Some(1i32);
    let b = Some(2i32);
    let c = |a, b| -> Option<i32> { Some(a? + b?) }(a, b);
    println!("hello, {:?}", c);
}

--
👇
cnwzhjs:

fn main()
{
    let a = Some(1);
    let b = Some(2);
    let c = match (a, b) {
        (Some(a), Some(b)) => Some(a+b),
        _  => None
    };
    println!("hello, {:?}", c);
}
作者 kaoet 2020-09-28 15:26

代码不等价。 我的例子里,merge(Some(1), None) = Some(1),你的代码中merge(Some(1), None) = None.

--
👇
cnwzhjs: 也可以用lambda:

fn main()
{
    let a = Some(1i32);
    let b = Some(2i32);
    let c = |a, b| -> Option<i32> { Some(a? + b?) }(a, b);
    println!("hello, {:?}", c);
}

--
👇
cnwzhjs:

fn main()
{
    let a = Some(1);
    let b = Some(2);
    let c = match (a, b) {
        (Some(a), Some(b)) => Some(a+b),
        _  => None
    };
    println!("hello, {:?}", c);
}
cnwzhjs 2020-09-28 15:24

还有一个nightly的api: std::option::Option::zip_with

--
👇
cnwzhjs: 也可以用lambda:

fn main()
{
    let a = Some(1i32);
    let b = Some(2i32);
    let c = |a, b| -> Option<i32> { Some(a? + b?) }(a, b);
    println!("hello, {:?}", c);
}

--
👇
cnwzhjs: ```rust fn main() { let a = Some(1); let b = Some(2); let c = match (a, b) { (Some(a), Some(b)) => Some(a+b), _ => None }; println!("hello, {:?}", c); }



cnwzhjs 2020-09-28 15:20

也可以用lambda:

fn main()
{
    let a = Some(1i32);
    let b = Some(2i32);
    let c = |a, b| -> Option<i32> { Some(a? + b?) }(a, b);
    println!("hello, {:?}", c);
}

--
👇
cnwzhjs: ```rust fn main() { let a = Some(1); let b = Some(2); let c = match (a, b) { (Some(a), Some(b)) => Some(a+b), _ => None }; println!("hello, {:?}", c); }


cnwzhjs 2020-09-28 15:19
fn main()
{
    let a = Some(1);
    let b = Some(2);
    let c = match (a, b) {
        (Some(a), Some(b)) => Some(a+b),
        _  => None
    };
    println!("hello, {:?}", c);
}
1 共 17 条评论, 1 页