where句と複数の境界
複雑なシグネチャを読みやすく保ちます。
「where句と複数の境界」はCoddyKit上の無料Learn Rust Codingレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn Rust Coding学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn Rust Codingコースには全4レッスンが含まれています。
インライン境界が複雑になったとき
<T: Display + Clone, U: Debug + Default> のようなインライン境界は、増えてくると読みにくくなります。Rust には、より読みやすい代替手段として where 句があります。
制約をシグネチャの下に移すことで、パラメータリストを短く保てます。
基本的な where 句
where 句は、戻り値の型と本体の間に置きます。各行に型とその境界を記述します。
この2つのシグネチャはまったく同じ意味で、where 形式の方が読みやすいだけです。
use std::fmt::Display;
fn show<T>(value: T)
where
T: Display,
{
println!("{}", value);
}where 句で複数の境界を指定する
複数の制約を、型パラメータごとに1つずつ、カンマで区切って記述できます。それぞれで + を使ってトレイトを組み合わせることもできます。
すべてをインラインに詰め込む場合と比べて、複雑なシグネチャでも読みやすくなります。
use std::fmt::{Display, Debug};
fn report<T, U>(a: T, b: U)
where
T: Display + Clone,
U: Debug,
{
println!("{} {:?}", a, b);
}完全な例
このプログラムでは、Display を要求する where 句を使っています。実行すると、各引数をラベル付きで出力します。
境界が付いていても、関数ヘッダーがすっきり保たれていることに注目してください。
use std::fmt::Display;
fn label<T>(name: &str, value: T)
where
T: Display,
{
println!("{} = {}", name, value);
}
fn main() {
label("age", 30);
label("city", "Oslo");
}コンパイラがインラインに書けない境界
関連型や参照先の型に対する境界など、where 句でしか記述できない境界があります。インライン構文では where Vec<T>: Clone を表現できません。
したがって、where 形式の方が表現力に優れています。
fn duplicate<T>(items: Vec<T>) -> (Vec<T>, Vec<T>)
where
Vec<T>: Clone,
{
(items.clone(), items)
}標準トレイトの組み合わせ
実際のコードでは、順序付け、コピー、出力を組み合わせた境界がよく使われます。このジェネリックな max_of は、スライス内で最大の要素を見つけます。
where 句で、アルゴリズムが依存する3つのトレイトをまとめています。
use std::fmt::Display;
fn max_of<T>(items: &[T]) -> &T
where
T: PartialOrd + Display,
{
let mut best = &items[0];
for item in items {
if item > best { best = item; }
}
best
}max_of を実行する
同じ考え方を実行可能なプログラムにした例です。整数のスライスは PartialOrd + Display を満たすため、呼び出しがコンパイルされ、最大値が出力されます。
この関数は、浮動小数点数や文字に対しても同じように動作します。
fn max_of<T>(items: &[T]) -> &T
where
T: PartialOrd,
{
let mut best = &items[0];
for item in items {
if item > best { best = item; }
}
best
}
fn main() {
let nums = [3, 7, 1, 9, 4];
println!("{}", max_of(&nums));
}impl ブロックでの where
where 句は impl ブロックにも付けられます。これにより、格納された型が Display を実装している場合にだけメソッドを追加できます。
T が Display でないインスタンスには、このメソッドは存在しません。
use std::fmt::Display;
struct Holder<T> { item: T }
impl<T> Holder<T>
where
T: Display,
{
fn print(&self) {
println!("{}", self.item);
}
}複数の境界を一度に指定する
実際のジェネリック API では、1つのパラメータに複数のトレイトを要求することがよくあります。このシグネチャでは、クローン、デバッグ、デフォルト値を要求しています。
where 句により、1つの型に3つの境界があっても読みやすく保てます。
use std::fmt::Debug;
fn build<T>() -> T
where
T: Default + Clone + Debug,
{
let v = T::default();
v.clone()
}インラインと where の使い分け
単純な制約が1つか2つだけなら、インライン境界を使います。パラメータが多い場合、トレイトの一覧が長い場合、または複雑な型に境界を付ける場合は where に切り替えます。
どちらも同一のコードにコンパイルされるため、選択基準は読みやすさだけです。
ライフタイムを伴う where
where 句には、トレイト境界とともにライフタイムの関係も記述できます。両方の制約を持つジェネリックシグネチャを整理して書けます。
ここでは、T がライフタイム 'a より長く存続することを要求しています。
fn keep<'a, T>(value: &'a T) -> &'a T
where
T: 'a,
{
value
}確認問題
where 句と複数の境界についての理解度を確認しましょう。
まとめ
where 句はトレイト境界をシグネチャの下に移し、パラメータやトレイトの一覧が増えたときの読みやすさを向上させます。また、インライン構文では表現できない複雑な型やライフタイムに対する境界も記述できます。
インライン境界と where 境界は同じようにコンパイルされるため、より読みやすい方を選びます。
よくある質問
「where句と複数の境界」レッスンは無料ですか?
はい。「where句と複数の境界」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn Rust Codingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn Rust Codingコースには全4レッスンが含まれています。
「where句と複数の境界」で何を学びますか?
複雑なシグネチャを読みやすく保ちます。 ブラウザで直接実行するハンズオンコードでLearn Rust Codingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Learn Rust Codingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLearn Rust Codingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「where句と複数の境界」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLearn Rust Codingレッスンでコードを書いて実行できますか?
はい。すべてのLearn Rust Codingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ジェネリック関数
- ジェネリックな構造体とenum
- トレイト境界
- where句と複数の境界