データ構造とは、複数の値をどのような形でまとめるかという設計です。
4.1 直積型
複数の値を同時に持つ構造です。
ユーザー = 名前 × 年齢 × メールアドレス
多くの言語ではクラス、構造体、レコードなどで表現します。
struct User {
name: String,
age: u32,
}
@dataclass
class User:
name: str
age: int
「名前と年齢の両方を持つ」ため、数学的には直積型と呼ばれます。
4.2 直和型
複数の候補のうち、いずれか一つを取る構造です。
結果 = 成功 または 失敗
Rustではenumで表現します。
enum Result<T, E> {
Ok(T),
Err(E),
}
TypeScriptではUnion型で表現できます。
type Result<T> =
| { type: "success"; value: T }
| { type: "error"; message: string };
直和型は、状態を安全に表現するための非常に重要な概念です。
4.3 代数的データ型
直積型と直和型を組み合わせたデータ構造を、代数的データ型と呼びます。
例えば注文状態を次のように表せます。
type OrderStatus =
| { type: "draft" }
| { type: "paid"; paidAt: Date }
| { type: "shipped"; trackingNumber: string }
| { type: "cancelled"; reason: string };
状態ごとに必要なデータが異なることを、型として表現しています。
悪い設計では、すべてを一つの構造へ入れます。
type Order = {
status: string;
paidAt?: Date;
trackingNumber?: string;
cancellationReason?: string;
};
この場合、矛盾した状態を作れます。
status = draft
trackingNumber = 存在する
cancellationReason = 存在する
直和型を使うと、不正な状態を作りにくくできます。
4.4 コレクション
代表的なコレクションには次があります。
| 構造 | 特徴 |
|---|---|
| 配列・リスト | 順序付きの値 |
| 集合 | 重複しない値 |
| マップ・辞書 | キーと値の対応 |
| キュー | 先入れ先出し |
| スタック | 後入れ先出し |
言語間で名前は違っても、データ構造としての性質は共通です。