对比Haskell和Rust中的自定义类型
Haskell中的data VS Rust中的enum
在Haskell中,我们可以通过data关键字定义新类型。最简单的类型声明使用了一个长度有限的值列表。例如,可以这样定义只有5个级别(10、J、Q、K、A)的扑克牌。
-- cards.hs
module Test where
data Suit = Spades | Hearts | Diamonds | Clubs
data Rank = Ten | Jack | Queen | King | Ace
在Rust中,可以用enum定义这样的一副扑克牌。
enum Suit {
Spades,
Hearts,
Diamonds,
Clubs,
}
enum Rank {
Ten,
Jack,
Queen,
King,
Ace,
}
当我们试图输出扑克牌的花色(如Hearts)时,无论是Haskell还是Rust,都报错了。
$ ghci
GHCi, version 9.4.7: https://www.haskell.org/ghc/ :? for help
ghci> :load cards.hs
[1 of 1] Compiling Test ( cards.hs, interpreted )
Ok, one module loaded.
ghci> Hearts
<interactive>:2:1: error:
• No instance for (Show Suit) arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
fn main() {
println!("{} {}", Suit::Hearts, Rank::Ace);
}
// Compiling playground v0.0.1 (/playground)
// error[E0277]: `Suit` doesn't implement `std::fmt::Display`
// --> src/main.rs:18:23
// |
// 18 | println!("{} {}", Suit::Hearts, Rank::Ace);
// | ^^^^^^^^^^^^ `Suit` cannot be formatted with the default formatter
// |
// = help: the trait `std::fmt::Display` is not implemented for `Suit`
报错的原因都是尝试显示花色,但却不知道如何显示。
若要显示自定义类型,在Haskell中可以继承Show函数,
-- cards.hs
module Test where
data Suit = Spades | Hearts | Diamonds | Clubs deriving (Show)
data Rank = Ten | Jack | Queen | King | Ace deriving (Show)
-- ghci> Hearts
-- Hearts
-- ghci> :set +t
-- ghci> Jack
-- Jack
-- it :: Rank
-- ghci> Clubs
-- Clubs
-- it :: Suit
在Rust中可以通过#[derive(Debug)]使用Debug这个trait,并配合:?或#:?这样的 format specifier;
#![allow(dead_code)]
#[derive(Debug)]
enum Suit {
Spades,
Hearts,
Diamonds,
Clubs,
}
#[derive(Debug)]
enum Rank {
Ten,
Jack,
Queen,
King,
Ace,
}
fn main() {
println!("{:?} {:?}", Suit::Hearts, Rank::Ace);
}
// Hearts Ace
也可以实现Display这个trait,
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5447530da96d95ce0f76fd6ee7dd3a4d
#![allow(dead_code)]
#[derive(Debug)]
enum Suit {
Spades,
Hearts,
Diamonds,
Clubs,
}
use std::fmt;
impl fmt::Display for Suit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Suit::Spades => write!(f, "♠️"),
Suit::Hearts => write!(f, "♥️"),
Suit::Diamonds => write!(f, "♦️"),
Suit::Clubs => write!(f, "♣️"),
}
}
}
#[derive(Debug)]
enum Rank {
Ten,
Jack,
Queen,
King,
Ace,
}
fn main() {
println!("{} {:#?}", Suit::Hearts, Rank::Ace);
}
// ♥️ Ace
安装Haskell
$ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
参考
《七周七语言》(Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming Languages)8.4.1 类与类型