跳转到内容

Rust 新手程序员/基本数学测试程序/特征和显示

来自维基教科书,开放的书籍,开放的世界

特征和显示

[编辑 | 编辑源代码]

Rust 中很少有魔法。我们之前学过的很多东西,以及之前使用过的很多东西,都可以在我们的代码中重新实现。我们希望在我们的程序中使用“{}”来直接显示运算符。

我们希望在 print_question() 中编写以下内容

fn print_question(num1: i32, num2: i32, operator: Operator) {
    println!("What is {} {} {}?", num1, operator, num2);
}

然而,如果我们尝试运行它,我们会得到以下消息

error[E0277]: `Operator` doesn't implement `std::fmt::Display`

Rust 中 println!() 之类的函数的工作原理是,当它看到“{}”时,它会检查逗号后的对应对象是否实现了名为“Display”的“特征”。特征就像类型上的标记,表明它具有可以使用的某些方法。

如果我们查看 std::fmt::Display 文档,我们会发现该特征具有

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

我们必须记住,这一切都在 std::fmt 下,所以我们必须在每个类型之前添加它。很多代码看起来很奇怪,但本质上我们必须编写一个与之匹配的函数,我们可以使用宏 write!() 来简化操作,如下所示

impl std::fmt::Display for Operator {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "+")
    }
}

std::fmt::Result 本身是 Result<(), Error> 的简写。同样,每个东西前面的 std::fmt:: 也很繁琐。我们可以这样做

use std::fmt;

放在顶部,并修改 Display 特征的实现,如下所示

impl fmt::Display for Operator {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "+")
    }
}

use 语句意味着,每当代码遇到 fmt 时,它就会假定它是 std::fmt。这有助于减少我们要编写的代码量,但如果我们有 fmt 的实例,也可能很危险,因为它无法区分。对于我们来说,这不太可能发生,因此我们可以放心地进行此更改。我们不必把它放在顶部,但通常情况下,我们希望将所有 use 语句放在同一个地方。也就是说,如果我们现在运行程序,我们会得到

What is 35 + 23?

糟糕,我们没有检查它是哪个运算符,现在让我们修复它

impl fmt::Display for Operator {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Operator::Addition => write!(f, "+"),
            Operator::Subtraction => write!(f, "-"),
        }
    }
}

现在如果我们运行程序,我们会得到

What is 35 - 23?

这就是我们想要的结果。

所有这些看起来可能有点复杂,但这样做有一些好处

  • 重用,我们现在可以轻松地在其他地方打印出运算符
  • 分解问题,我们不希望所有内容都在同一个函数或同一个地方。这样一来,Operator 类型和功能就可以与程序的其他部分分离。
  • 易于编辑,因为所有内容都在同一个地方,我们只需要更改 Operator 类型和相关函数中的逻辑,所有在其他地方使用它的地方都将是正确的。

接下来:我们将研究如何接收用户输入

华夏公益教科书