rust: Rustがんばろう 16日目
2025/04/15
はじめに
まだトレイト。
10.2章
このページも残るは小見出し 2つだけだ。
実装していないトレイト関数は受け付けない
演算子のように、ぱっと見た目でトレイトと関係しているように見えなくても 結構トレイトになっている。
ジェネリック型のつもりで T
を使った関数を作って値の比較をしたけれどもコンパイルエラーになる。
これは <
や >
が trait PartialOrd
のトレイト関数?だからで、
つまり T
が trait PartialOrd
を持っていないというエラーだ。
PartialOrd
は “partial order” らしいが、ord()
は他の言語でも見かける関数だったがどこでだったか。
検索すると Python が出てくるのでそうかもしれない。
あれも order の略だったんだろうか?
「部分的な順番」かと思ったのだが 前順序集合、半順序集合 というものだそうだ。
わざわざ英語版の wikipedia のリンクがあったのでそうなんだろう。
普段は wikipedia 見ないのに、こういう時期だけ目にしてしまうのだよな。
存続してほしいので今年も払いますが。
ともかく。
半順序(partial order) に「半」が付くので、そうではない全集合(total order)というのもある。
こちらも trait Ord として存在している。
- PartialEq:
==
,!=
- PartialOrd:
PartialEq
と<
,<=
,>
,>=
。あとpartial_cmp
。 - Eq:
PartialEq
と同じ? - Ord):
Eq
+PartialOrd
とcmp
,max
,min
,clamp
集合論的にはいろいろ段階があるのだろうけど、反射律と推移律と反対称律を満たすと不等号が使えるのはなんとなく分かる。 これに全順序律を加えるというのがよくわからん。 集合に対して必ず不等号による判定が付けられるという意味だろうか。
いや、そういうのはさておくとして、Ord
は PartialOrd
に比較するメソッドがいくつか追加されただけのようだったので、
どっちか片方に寄せてしまえばよかったのでは、と思ったのだが PartialOrd
に説明してあった。
This trait should only contain the comparison logic for a type if one plans on only implementing PartialOrd but not Ord. PartialOrd のみを実装し、Ord は実装しない予定の場合、このトレイト(PartialOrd)には型の比較ロジックのみを含める必要があります
Otherwise the comparison logic should be in Ord and this trait implemented with Some(self.cmp(other)). それ以外の場合は、比較ロジックはOrdに含め、このトレイト(PartialOrd)はSome(self.cmp(other))で実装する必要があります。
うーん・・・。
説明というか、こうしなさいという指示だ。
めんどう!というかよくわからん。
試しにサンプルコードの largest()
を PartialOrd
から Ord
にしても特にエラーは出ないし動く。
まあ、PartialOrd
を継承?した Ord
だから当たり前か。使った型もプリミティブ型だし。
vscode で編集して where
と入力すると自動で PartialOrd + Copy
が補完された。
これはコードの内容を把握してだろうか? あるいはこのドキュメントがそうなっているからまねしただけだろうか。
Tweet
のインスタンスも途中まで打ち込むとこのドキュメントの内容が自動で補完されたので後者のような気もする。
trait Copy
を外すのは &
を付けて回るだけで済んだ。
プリミティブ型だと参照にした方が遅くなったりするのかな?
アドレス先を読み取ってレジスタに代入するか、アドレスをレジスタに入れて参照するかの違いだとそこまで変わらん気はする。
実装してないトレイトを呼べないようにする
impl<T>
を impl<T: Trait>
にすると、それで実装したメソッドを呼べるのはインスタンスがそのトレイトを持っているときだけ。
それはそうだろうと思ったが、言語によっては未実装があるとコンパイルできないから空実装するようなことがなかったっけ。 まあよく覚えていないが、Rust だと静的に確定しないとビルドエラーになると思うので、わかりやすいはずだ。
もう1つの「ブランケット実装(blanket implementation)」。
“blanket” は「全体的な」とか「無差別な」だそうなので、「この trait bound のインスタンスなら何でも呼び出せますよ」ということになる。
毛布のことじゃないんだね。。。
ジェネリックとかトレイトは、型チェックが厳しい Rust でも型ごとに実装しないといけないのを回避するのに使えそうだ。
そう思って <T, U>
の両方を PartialOrd + Copy
にして、引数 2つがどういうやつでも比較して大きい方を返す関数、
みたいなのを作ろうとしたが、これは T
と U
が同じ型ではないから比較ができずにダメだった。
as u32
で取りあえず同じ型にしてみようとしたけど、それもダメだった。
なんかありそうな気はするんだけど、できないようにしているという気もする。
まだ Rust 慣れしてないねー。
おわりに
ようやくトレイトのところを通り過ぎることができた。
雰囲気は分かったような気がする、くらいだな。