サンプルコードで身につける: トレイト境界 — ジェネリクスに条件を付ける
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1PartialOrd 境界で比較を許可する
2つの値の大きい方を返すには、T が比較できる型である保証が必要です。<T: PartialOrd> という境界を付けることで、関数の中で > が使えるようになります。境界を消すとコンパイルエラーになるので、「中で使う操作は境界で宣言する」という対応関係を確かめてみてください。
2Display 境界 — 表示にも条件が要る
ジェネリックな値を {} で表示することすら、T が Display を実装している保証がないとできません。境界は比較だけでなく「表示できる」「複製できる」などあらゆる操作の宣言に使う、と分かる例です。Display は標準ライブラリのトレイトで、use で持ち込んで境界に書けます。
3+ で複数の境界を組み合わせる
スライスから最大値を「値として」返すには、比較のための PartialOrd と、参照から値を取り出すための Copy の両方が必要です。境界は + でいくつでも重ねられ、関数内の操作が増えるほど境界も増えます。コースの前半で学んだ Copy が、ジェネリクスの条件として再登場している点にも注目です。
4where 句で境界を整理する
型パラメータが増えて境界が長くなると、シグネチャの < > の中が読みにくくなります。where 句を使えば「引数と戻り値」と「型への条件」を行で分けて書けます。意味は <T: Display, U: Display> とまったく同じで、実務のコードでは境界が2つ以上になったら where に逃がす書き方をよく見かけます。
5境界付きのジェネリック構造体
計測値の最小・最大を追跡する Tracker を、要素の型を問わない構造体として作った例です。境界は struct 側ではなく impl<T: PartialOrd + Copy> に付けるのが定番で、「このメソッド群を使うなら比較とコピーができる型で」という条件になります。温度でもレスポンスタイムでも同じ型で集計できる、実務寄りの形です。