LoginSignup
47
38

More than 1 year has passed since last update.

Rustの構造体などに追加できる振る舞いを確認する

Last updated at Posted at 2018-12-24

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

同じ値を持つ構造体ですがアドレスが別になっています

参考資料

47
38
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
38