等価性のトレイト
CoddyのRustジャーニー「Object Oriented Programming」セクションの一部 — レッスン 38/61。
Rustでは、カスタム構造体の2つのインスタンスを==で比較することは、デフォルトでは動作しません。コンパイラは2つの構造体が等しいかどうかを判断する方法を知らないため、PartialEqトレイトを実装してそれを伝える必要があります。
DebugやCopyと同様に、PartialEqを自動的に派生(derive)させることができます:
#[derive(PartialEq)]
struct Coordinate {
x: i32,
y: i32,
}
let a = Coordinate { x: 5, y: 10 };
let b = Coordinate { x: 5, y: 10 };
let c = Coordinate { x: 3, y: 7 };
println!("{}", a == b); // true
println!("{}", a == c); // false
派生された場合、PartialEq は構造体の各フィールドを比較します。2つのインスタンスは、対応するすべてのフィールドが一致する場合にのみ等しいとみなされます。
また、Eq にも遭遇するでしょう。これは**完全な一致(total equality)**を示すマーカートレイトであり、すべての値が自分自身と等しいことを意味します。ほとんどの型はこの性質を満たしますが、浮動小数点数は満たしません(NaN != NaN であるためです)。整数フィールドを持つ構造体の場合、両方を安全に derive できます:
#[derive(PartialEq, Eq)]
struct Coordinate {
x: i32,
y: i32,
}
Eq は独自のメソッドを持ちません。単にその型が反射的な等価性を持つことを示すだけです。一部の標準ライブラリの機能は PartialEq に加えて Eq を必要とするため、条件を満たす型に対しては両方を一緒に derive するのが一般的です。
チャレンジ
簡単PartialEq と Eq トレイトによって構造体のインスタンス間の比較がどのように可能になるかを示す、カラーマッチングシステムを構築しましょう!
カラー比較ロジックを整理するために、2つのファイルを作成します:
color.rs: 3つのパブリックフィールドred、green、blue(すべてu8型)を持つパブリックなColor構造体を定義します。PartialEqとEqの両方を派生(derive)させ、2つの色を==で比較できるようにします。派生させた場合、Rustは3つのRGBコンポーネントすべてが完全に一致する場合のみ、2つの色が等しいとみなします。main.rs: 作成したカラーモジュールを取り込み、提供された入力を使用して2つのColorインスタンスを作成します。それらを==を使って比較し、一致するかどうかを出力します。
出力は、2つの色が同じかどうかを示す必要があります:
Color 1: rgb({r1}, {g1}, {b1})
Color 2: rgb({r2}, {g2}, {b2})
Colors match: {true/false}例えば、入力が 255, 128, 0, 255, 128, 0 の場合:
Color 1: rgb(255, 128, 0)
Color 2: rgb(255, 128, 0)
Colors match: trueまた、入力が 100, 100, 100, 200, 200, 200 の場合:
Color 1: rgb(100, 100, 100)
Color 2: rgb(200, 200, 200)
Colors match: false6つの入力を受け取ります:最初の色のRGB値(3つの値)、続いて2番目の色のRGB値(3つの値)です。それぞれを u8 としてパースしてください。
チートシート
== を使用してカスタム構造体を比較するには、PartialEq トレイトを派生(derive)させて実装します:
#[derive(PartialEq)]
struct Coordinate {
x: i32,
y: i32,
}
let a = Coordinate { x: 5, y: 10 };
let b = Coordinate { x: 5, y: 10 };
println!("{}", a == b); // true
派生させた場合、PartialEq はすべてのフィールドを比較します。2つのインスタンスは、対応するすべてのフィールドが一致する場合にのみ等しいとみなされます。
Eq トレイトは、完全な等価性(すべての値が自分自身と等しいこと)を示すマーカートレイトです。浮動小数点数(NaN != NaN であるため)を除き、ほとんどの型がこれを満たします。整数フィールドを持つ構造体の場合、両方のトレイトを一緒に派生させます:
#[derive(PartialEq, Eq)]
struct Coordinate {
x: i32,
y: i32,
}
Eq にはメソッドはありません。これは反射的な等価性を合図するものです。標準ライブラリの一部の機能では、PartialEq に加えて Eq が必要になります。
自分で試してみよう
mod color;
use color::Color;
fn main() {
// 6つのRGB値を読み込む
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let r1: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let g1: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let b1: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let r2: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let g2: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let b2: u8 = input.trim().parse().expect("Invalid input");
// TODO: 解析した値を使用して2つの Color インスタンスを作成する
// TODO: Color 1 を次の形式で出力する: Color 1: rgb(r, g, b)
// TODO: Color 2 を次の形式で出力する: Color 2: rgb(r, g, b)
// TODO: == を使用して2つの色を比較し、次のように出力する: Colors match: {true/false}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。