Python 是一門可愛的語言。然而,在使用 Python 時,我經常發現自己缺少對總和類型的內建支援。像 Haskell 和 Rust 這樣的語言讓這種事情變得如此簡單:
雖然 Python 不支援這種開箱即用的構造,但我們將看到像 Expr 這樣的類型仍然可以(並且容易)表達。此外,我們可以創建一個裝飾器來為我們處理所有令人討厭的樣板檔案。結果與上面的 Haskell 範例沒有太大不同:
我們將使用「標記聯合」來表示總和型別。透過範例很容易理解:
每個變體都是同一類別的實例(在本例中為 Expr)。每個都包含一個“標籤”,指示它是哪個變體,以及特定於它的數據。
使用 Expr 最基本的方法是使用 if-else 鏈:
但是,這有一些缺點:
我們可以透過公開用於消耗總和類型的單一公共匹配方法來避免所有這些問題:
但首先我們需要讓不同的變體更統一。每個變體現在不再將其資料儲存在各個欄位中,而是將其儲存在名為 data 的元組中:
這使我們能夠實現匹配:
我們一舉解決了上述所有問題!作為另一個例子,為了換個環境,這是以這種方式轉錄的 Rust 選項類型:
作為生活品質的一項小福利,我們可以在匹配中支援特殊的通配符或「包羅萬象」的處理程序,用下劃線 (_) 表示:
這允許我們使用以下匹配:
如 Option 類別所示,創建總和類型所需的許多程式碼都遵循相同的模式:
我們不用自己寫這個,而是寫一個裝飾器來根據變體的一些描述來產生這些方法。
什麼樣的描述?最簡單的事情是提供變體名稱列表,但我們也可以透過提供我們期望的參數類型來做得更好。我們將使用枚舉來自動增強我們的 Option 類,如下所示:
枚舉的基本結構如下:
這是一個傳回另一個函數的函數,該函數將使用我們正在增強的類別作為其唯一參數來呼叫。在增強中,我們將附加用於構建每個變體的方法以及匹配。
首先,匹配,因為它只是複製義大利麵:
加入方法來建構每個變體只是稍微複雜一些。我們迭代變體字典,為每個條目定義一個方法:
其中 make_constructor 為帶有標籤(和名稱)標籤和「類型簽名」sig 的變體建立建構函式:
這裡是 enum 的完整定義,供參考。
我們可以使用 __repr__ 和 __eq__ 方法輕鬆增強我們的 sum 類別:
透過以這種方式改善增強功能,我們可以以最小的方式定義選項:
不幸的是,枚舉(還)無法完成定義 Expr 的任務:
我們在定義類別 Expr 之前使用它。這裡一個簡單的解決方法是在定義類別後簡單地呼叫裝飾器:
但是我們可以做一個簡單的改變來支持這一點:允許「簽章」是一個返回元組的函數:
所有這些都需要對 make_constructor 進行一些小的更改:
儘管我們精美的新枚舉裝飾器可能很有用,但它也有其缺點。最明顯的是無法執行任何類型的“嵌套”模式匹配。在 Rust 中,我們可以做這樣的事情:
但是我們被迫執行雙重配對才能得到相同的結果:
也就是說,這類案例似乎相對很少見。
另一個缺點是匹配需要建構和呼叫大量函數。這意味著它可能比等效的 if-else 鏈慢得多。然而,通常的經驗法則適用於此:如果您喜歡枚舉的人體工學優勢,請使用枚舉;如果它太慢,則將其替換為“生成的”代碼。
以上是Python 中的求和型的詳細內容。更多資訊請關注PHP中文網其他相關文章!