Help us understand the problem. What is going on with this article?

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

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

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

参考資料

https://doc.rust-jp.rs/book/second-edition/appendix-03-derivable-traits.html

microad
データとテクノロジーをかけ合わせたマーケティングプラットフォームを提供する会社です。
https://www.microad.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away