Return value if passes predicate, else default

我是研究僧i 提交于 2019-12-11 07:34:41

问题


How can I replace a value if it fails a predicate?

To illustrate:

assert_eq!((3-5).but_if(|v| v < 0).then(0), 0)

I thought there would be something on Option or Result to allow this, but I cannot find it.


回答1:


I thought there would be something on Option or Result

But neither of these types appear here. Subtracting two numbers yields another number.

It appears you just want a traditional if-else statement:

fn main() {
    let a = 3 - 5;
    assert_eq!(if a < 0 { 0 } else { a }, 0);
}

Since you have two values that can be compared, you may also be interested in max:

use std::cmp::max;

fn main() {
    assert_eq!(max(0, 3 - 5), 0);
}

You can make your proposed syntax work, but I'm not sure it's worth it. Presented without further comment...

fn main() {
    assert_eq!((3 - 5).but_if(|&v| v < 0).then(0), 0)
}

trait ButIf: Sized {
    fn but_if<F>(self, f: F) -> ButIfTail<Self>
        where F: FnOnce(&Self) -> bool;
}

// or `impl<T> ButIf for T {` for maximum flexibility
impl ButIf for i32 {
    fn but_if<F>(self, f: F) -> ButIfTail<Self>
        where F: FnOnce(&Self) -> bool,
    {
        ButIfTail(f(&self), self)
    }
}

struct ButIfTail<T>(bool, T);

impl<T> ButIfTail<T> {
    fn then(self, alt: T) -> T {
        if self.0 {
            alt
        } else {
            self.1
        }
    }
}



回答2:


Update: This got a bit nicer since Rust 1.27, when Option::filter was added:

assert_eq!(Some(3 - 5).filter(|&v| v >= 0).unwrap_or(0), 0);

Prior to Rust 1.27, you would have needed an iterator in order to write a single, chained expression without lots of additional custom machinery:

assert_eq!(Some(3 - 5).into_iter().filter(|&v| v >= 0).next().unwrap_or(0), 0);


来源:https://stackoverflow.com/questions/41384597/return-value-if-passes-predicate-else-default

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!