跳轉到內容

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 型別和相關函式中的邏輯,所有在其他地方使用它的地方都將是正確的。

接下來:我們將研究如何接收使用者輸入

華夏公益教科書