我可以在匹配中使用 '<' 和 '>' 吗?

46

我正在尝试做一个简单的二次函数,通过枚举返回根数及其值:

enum QuadraticResult {
    None,
    OneRoot(f32),
    TwoRoots(f32, f32),
}

fn solveQuadratic(a: f32, b: f32, c: f32) -> QuadraticResult {
    let delta = b * b - 4.0 * a * c;
    match delta {
        < 0 => return QuadraticResult::None,
        > 0 => return QuadraticResult::TwoRoots(0.0, 1.0),
        _ => return QuadraticResult::OneRoot(0.0),
    }
}

这段代码无法编译,因为它报错了 '<' 和 '>'。是否有一种使用 match 实现的方法,或者我需要使用 if 语句?


1
惯用的 Rust 使用 snake_case 作为标识符。不要使用 solveQuadratic,而是使用 solve_quadratic - Shepmaster
@Shepmaster 很好的观点。幸运的是,在我编译成功后,Visual Studio Code 的 rls 插件也为我标记了这个问题。 :) - dawid
3
我猜你最终会用计算出的值替换 0.01.0。注意不要假设当返回 QuadraticResult::TwoRoots(x, y) 时,x != y。即使 d 大于 0,-b + d.sqrt()-b - d.sqrt() 仍然可能相同。这里有一个简单的例子,但它也可能发生在有限的根上。你可能想要返回 Option<(x1, x2)> 并让调用者决定 x1x2 是否“足够接近”以被视为单个根。 - trent
4个回答

71

你可以使用匹配守卫,但这似乎比普通的if语句更冗长:

return match delta {
    d if d < 0 => QuadraticResult::None,
    d if d > 0 => QuadraticResult::TwoRoots(0.0, 1.0),
    _   => QuadraticResult::OneRoot(0.0),
}

8
我想补充一下,在这种情况下,我肯定更喜欢“匹配”而不是“if/else”语句,因为在我看来,代码看起来更整洁和可读。 - dawid
另外想到一件事。在“if/else”和“match”之间是否存在明显的性能差异? - dawid
4
即使您在性能上有任何差异,也不能保证它会在下一个版本中保持不变。如果没有被迫这样做,您不应该在这个层面上过于关注性能。首要的是可读性,优化是编译器的工作。您可以在此处检查match和if的汇编代码 - S.R

30

如果你想处理某个值大于、等于或小于另一个值的三种情况,可以使用Ordering进行匹配,其中Ordering可以通过调用cmp(来自Ord trait)或partial_cmp(来自PartialOrd trait)获得。

fn solve_quadratic(a: f32, b: f32, c: f32) -> QuadraticResult {
    let delta = b * b - 4.0 * a * c;
    match delta.partial_cmp(&0.0).expect("I don't like NaNs") {
        Ordering::Less => QuadraticResult::None,
        Ordering::Greater => QuadraticResult::TwoRoots(0.0, 1.0),
        Ordering::Equal => QuadraticResult::OneRoot(0.0),
    }
}

11

你可以这样做,但是在执行时你需要创建一个变量绑定,并将其转换为实际表达式:

match delta {
    d if d < 0.0 => QuadraticResult::None,
    d if d > 0.0 => QuadraticResult::TwoRoots(0.0, 1.0),
    _ => QuadraticResult::OneRoot(0.0),
}

我不确定这种方法是否比将其拆分为一个if语句好。


谢谢你,Simon。我必须接受Jacob的答案,因为他先回答了 :) - dawid
哦,一点问题也没有。我没有看到雅各布的答案...哈哈,它们几乎完全相同!我可能也应该删除我的回答。 - Simon Whitehead

1
警告:自rustc 1.67.0 (fc594f156 2023-01-24)起,此方法仍然有效,但将在未来的版本中停止支持浮点字面量
您可以使用范围模式,这在匹配表达式中得到支持。这需要开启exclusive_range_pattern功能。
#![feature(exclusive_range_pattern)]
fn solveQuadratic(a: f32, b: f32, c: f32) -> QuadraticResult {
    let delta = b * b - 4.0 * a * c;
    match delta {
        std::f32::MIN..0.0 => return QuadraticResult::None,
        0.0 => return QuadraticResult::OneRoot(0.0),
        _ => return QuadraticResult::TwoRoots(0.0, 1.0),
    }
}

游乐场


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接