Rustではderive
を使用して構造体や列挙型などに振る舞いを追加することができます。
ここでは標準ライブラリで使える主要なものの動きを確認してみます。
Debug
デバック出力を行えるように振る舞いを追加します。
println!
マクロを使用する際に{:?}
というデバック出力用のフォーマットを指定することでデバック出力を表示させることができます。
#[derive(Debug)]
struct Data{
value: i32,
}
fn main() {
let d = Data {value: 2};
println!("{:?}", d);
}
出力
Data { value: 2 }
PartialEq
オブジェクト同士が等価であることを比較するための振る舞いを追加します。
#[derive(Debug,PartialEq)]
struct Data{
value: i32,
}
fn main() {
let d1 = Data {value: 2};
let d2 = Data {value: 2};
assert_eq!(d1, d2);
}
Eq
同じ値での比較がすべての値で真に成る場合に付与できる振る舞いです。
たとえば、浮動小数点数型はNaN値同士の比較が真にならないのでEq
が実装されていません。
構造体の場合はEq
が実装されていないメンバを持つ時にEq
の振る舞いを付与しようとするとコンパイルエラーになります。
ちなみにEq
を実装するには予めPartialEq
も実装してある必要があります。
#[derive(Debug,PartialEq,Eq)]
struct Data{
value: i32,
}
fn main() {
let d1 = Data {value: 2};
let d2 = Data {value: 2};
assert_eq!(d1, d2);
}
PartialOrd
大小を比較するための振る舞いを追加します。
構造体は複数のフィールド持つ場合がありますが、その場合は先に定義されたものから順番に比較が行われます。
ちなみにPartialEqも一緒に実装されている必要があります。
#[derive(PartialEq,PartialOrd)]
struct Data{
value: i32,
}
fn main() {
let d1 = Data {value: 2};
let d2 = Data {value: 1};
assert!(d1 > d2);
}
Ord
順序付け不能な値が存在しない物だけに追加できる振る舞いです。
例えば浮動小数点型ではNaNという順序付け不能な値が存在するのでOrdを実装することができません。
下記の例ではOrdの振る舞いを使用してソートするsort
メソッドを使用しています
#[derive(Debug,PartialEq,Eq,PartialOrd,Ord)]
struct Data{
value: i32,
}
fn main() {
let d1 = Data {value: 2};
let d2 = Data {value: 1};
let d3 = Data {value: 3};
let mut s = [d1, d2 ,d3];
s.sort();
print!("{:?}", s);
}
出力
[Data { value: 1 }, Data { value: 2 }, Data { value: 3 }]
Clone
クローン可能になる振る舞いを追加します。
下記の例ではクローンされたオブジェクトのポインタが異なっていることを出力しています。
#[derive(Debug,Clone)]
struct Data{
value: i32,
}
fn main() {
let d1 = Data {value: 2};
let d2 = d1.clone();
// アドレスの取得
let raw_d1 = &d1 as *const Data;
let raw_d2 = &d2 as *const Data;
println!("d1: {:?}", d1);
println!("d1 pointer: {:?}", raw_d1);
println!("d2: {:?}", d1);
println!("d2 pointer: {:?}", raw_d2);
}
出力例
d1: Data { value: 2 }
d1 pointer: 0x7ffd0ec0f4a0
d2: Data { value: 2 }
d2 pointer: 0x7ffd0ec0f4a8
同じ値を持つ構造体ですがアドレスが別になっています
Copy
=演算子を使用したときに所有権の移動ではなく、クローンを行う振る舞いを追加します。
Copy
を実装するにはClone
も実装されている必要があります。
#[derive(Debug,Clone,Copy)]
struct Data{
value: i32,
}
fn main() {
let d1 = Data {value: 2};
let d2 = d1;
// アドレスの取得
let raw_d1 = &d1 as *const Data;
let raw_d2 = &d2 as *const Data;
println!("d1: {:?}", d1);
println!("d1 pointer: {:?}", raw_d1);
println!("d2: {:?}", d1);
println!("d2 pointer: {:?}", raw_d2);
}
出力例
d1: Data { value: 2 }
d1 pointer: 0x7ffc21f69990
d2: Data { value: 2 }
d2 pointer: 0x7ffc21f69998
同じ値を持つ構造体ですがアドレスが別になっています
参考資料