【问题标题】:Why do we use the Option enum?为什么我们使用 Option 枚举?
【发布时间】:2019-10-23 13:11:22
【问题描述】:

我不明白 Option 枚举的用途。我读到 Rust 没有空值。 Option 枚举定义如下:

enum Option<T> {
    Some(T),
    None,
}

我阅读了它的实现并遇到了这个例子:

fn main() {
    fn divide(numerator: f64, denominator: f64) -> Option<f64> {
        if denominator == 0.0 {
            None
        } else {
            Some(numerator / denominator)
        }
    }

    // The return value of the function is an option
    let result = divide(2.0, 3.0);

    // Pattern match to retrieve the value
    match result {
        // The division was valid
        Some(x) => println!("Result: {}", x),
        // The division was invalid
        None => println!("Cannot divide by 0"),
    }
}

当他们也可以这样做时:

fn main() {
    fn divide(numerator: f64, denominator: f64) -> String {
        if denominator == 0.0 {
            format!("Can't divide")
        } else {
            let x = numerator / denominator;
            format!("{}", x)
        }
    }

    let result = divide(2.0, 3.0);
    println!("{}", result);
}

两个程序的输出:

0.6666666666666666

【问题讨论】:

  • 我当然不想将我的数字格式化为字符串,这样我就可以解析它并将其转换回数字。那将是极其低效且丑陋的代码。原始代码是使用 Option 的一个很好的例子。

标签: enums rust


【解决方案1】:

使用Option enum 的原因与使用Result 枚举的原因相同。它允许程序员查看他们可能收到的返回值的广度,而无需深入研究您不记得或从未见过的所有细节的代码。

Option 不是一个特殊值,它只是一个枚举,比如Result。你也可以使用类似的东西:

enum Division_Result {
    Successful(f64),
    DividedByZero,
}

fn divide(numerator: f64, denominator: f64) -> Division_Result {
    if denominator == 0.0 {
        Division_Result::DividedByZero
    } else {
        Division_Result::Successful(numerator / denominator)
    }
}

碰巧可选值是您必须在程序中处理的一些最常见的值类型。他们将 Optional 枚举纳入标准,否则您将不得不处理每个人都提出自己的 enum 以获取 Optional 值的简单概念。

返回 enum 是对返回未包装的魔法值的改进,因为对于程序员来说,返回值可能与他们想要的函数不同。

【讨论】:

    【解决方案2】:

    也许上面的例子不是Option的一个很好的例子,但是下面的例子展示了Option的最佳状态:

    fn main() {
        let name = String::from("naufil");
        println!(
            "Character at index 6: {}",
            match name.chars().nth(6) {
                Some(c) => c.to_string(),
                None => "No character at index 6!".to_string(),
            }
        )
    }
    

    当我们不确定第 6 个元素是否有字符并且您不希望程序崩溃时,Option 会来救援。这是The Rust Programming Language的另一个例子:

    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }
    
    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
    

    示例 6-5:一个使用 match 表达式的函数 Option&lt;i32&gt;

    让我们更详细地检查plus_one 的第一次执行。当我们打电话 plus_one(five)plus_one 主体中的变量 x 将具有 值Some(5)。然后我们将其与每个匹配臂进行比较。

    None => None,
    

    Some(5) 值与模式 None 不匹配,因此我们继续 下一个手臂。

    Some(i) => Some(i + 1),
    

    Some(5) 是否匹配 Some(i)?为什么是的!我们有相同的变体。这 i 绑定到 Some 中包含的值,因此 i 采用值 5。这 然后执行匹配臂中的代码,因此我们将 i 的值加 1 和 创建一个新的Some 值,其中包含我们的总6

    现在让我们考虑在示例 6-5 中第二次调用 plus_one,其中 xNone。我们输入match 并与第一臂进行比较。

    None => None,
    

    匹配!没有要添加的值,所以程序停止并返回 None 值在 =&gt; 的右侧。因为第一个手臂匹配,没有其他 比较武器。

    结合match 和枚举在许多情况下很有用。你会看到这个 在 Rust 代码中很多模式:match 针对枚举,将变量绑定到 里面的数据,然后根据它执行代码。一开始有点难,但是 一旦你习惯了它,你会希望你拥有所有语言的它。它的 一直是用户的最爱。

    【讨论】:

      猜你喜欢
      • 2014-05-14
      • 2010-10-09
      • 2018-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-25
      • 2018-11-16
      • 1970-01-01
      相关资源
      最近更新 更多