Rustの==, !=演算子とeq, neメソッドおよびPartialEq, Eqトレイト
Rustでは、==
, !=
演算子によって2つの値が等しいかどうかを判定できる。x == y
, x != y
の実体はx.eq(&y)
, x.ne(&y)
であり、eq
, ne
メソッドはPartialEq
トレイトに含まれている。
以下のサンプルコードでは、説明のため、型推論によって省略できるときも明示的に型注釈を記述している場合がある。
また、サンプルコード中でassert!
マクロを使っている。コメントアウトしていない場合、引数の式がtrue
と評価されることを示している。
==, !=演算子とeq, neメソッド
==
演算子は、左辺と右辺の値が等価であるとtrue
、等価でないとfalse
を返す。!=
演算子はその逆。
let result: bool = 2 + 2 == 4;
println!("{result}");
// true
let result: bool = 2 + 2 == 5;
println!("{result}");
// false
let result: bool = 2 + 2 != 4;
println!("{result}");
// false
let result: bool = 2 + 2 != 5;
println!("{result}");
// true
==
, !=
の実体はeq
, ne
メソッドであり、x == y
, x != y
は、x.eq(&y)
, x.ne(&y)
と書ける。
let a: i32 = 10;
let b: i32 = 10;
let c: i32 = 100;
assert!(a == b);
assert!(a.eq(&b));
assert!(a != c);
assert!(a.ne(&c));
eq
, ne
メソッドはPartialEq
トレイトに含まれている。
==, !=演算子で比較できる型、できない型
型A
, B
の値a
, b
があるとき、PartialEq<B> for A
が実装されていると、a.eq(&b)
, a.ne(&b)
すなわちa == b
, a != b
の比較が可能。
PartialEq
がどのような型で実装されているかは「Implementors」の節に一覧になっている。
例えばi32
の場合、PartialEq<i32> for i32
のみが実装されているので、i32
の値同士でしか比較できない。異なる型の値との比較はコンパイルエラーになる。型を揃えれば比較可能。他の数値型も同じ。
let i_32: i32 = 100;
let i_64: i64 = 100;
// assert!(i_32 == i_64);
// assert!(i_32.eq(&i_64));
// error[E0308]: mismatched types
assert!(i_32 as i64 == i_64);
一方、例えば文字列String
と文字列スライス&str
の場合、PartialEq<&str> for String
とPartialEq<String> for &str
(実際はライフタイム注釈が付く)が実装されているので、互いに比較可能。
- PartialEq in std::cmp - PartialEq<&'a str> for String - Rust
- PartialEq in std::cmp - PartialEq<String> for &'a str - Rust
let s_str: &str = "abc";
let s_string: String = String::from("abc");
assert!(s_str == s_string);
assert!(s_str.eq(&s_string));
assert!(s_string == s_str);
assert!(s_string.eq(&s_str));
また、ベクタVec<T>
と配列[T; N]
の場合、PartialEq<[U; N]> for Vec<T, A>
は実装されているが逆は実装されていないので、順番によってはコンパイルエラーとなる。
let v: Vec<i32> = vec![10, 20, 30];
let a: [i32; 3] = [10, 20, 30];
assert!(v == a);
assert!(v.eq(&a));
// assert!(a == v);
// assert!(a.eq(&v));
// error[E0277]: can't compare `[i32; 3]` with `std::vec::Vec<i32>`
PartialEq, Eqトレイト
PartialEq
トレイトは対称および推移の特性を保証する。
例えば、型A
の値a1
, a2
, a3
があるとき、PartialEq<A> for A
が実装されていると以下の特性が成り立つ。
- 対称(Symmetric):
a1 == a2
ならばa2 == a1
- 推移(Transitive):
a1 == a2
,a2 == a3
ならばa1 == a3
Eq
トレイトは対称、推移に加えて、反射の特性を保証する。
- 反射(Reflexive):
a1 == a1
Eq
トレイトはメソッドを持たず、その特性を保証するマーカートレイトとして使われる。例えばHashMap<K, V>
のキーK
はEq
を実装している必要がある。
例えば、浮動小数点数f32
, f64
には非数NaN
が含まれる。NaN != NaN
であるため、f32
, f64
にはPartialEq
は実装されているが、Eq
は実装されていない(実装できない)。したがって、f32
, f64
をHashMap
のキーにすることはできない。
PartialEqの特性についての補足
PartialEq
の対称および推移の特性を、異なる型の値も含めて一般化すると以下のようになる。
- 対称(Symmetric)
- 型
A
,B
の値a
,b
があるとき、PartialEq<B> for A
,PartialEq<A> for B
が実装されていると、a == b
ならばb == a
- 型
- 対称性(Symmetric)
- 型
A
,B
,C
の値a
,b
,c
があるとき、PartialEq<B> for A
,PartialEq<C> for B
,PartialEq<C> for A
が実装されていると、a == b
,b == c
ならばa == c
- 型
The equality relation
==
must satisfy the following conditions (for alla
,b
,c
of typeA
,B
,C
):
- Symmetric: if
A: PartialEq<B>
andB: PartialEq<A>
, thena == b
impliesb == a
; and- Transitive: if
A: PartialEq<B>
andB: PartialEq<C>
andA: PartialEq<C>
, thena == b
andb == c
impliesa == c
.Note that the
B: PartialEq<A>
(symmetric) andA: PartialEq<C>
(transitive) impls are not forced to exist, but these requirements apply whenever they do exist. PartialEq in std::cmp - Rust
最後に注釈がついているが、ベクタVec<T>
と配列[T; N]
の例のように、PartialEq<B> for A
が実装されているときに必ずPartialEq<A> for B
が実装されているとは限らないので注意。