📝

derive

に公開

deriveとは、構造体や列挙型に対して特定のトレイトを自動的に実装するための仕組み。
#[derive(trait)]というアトリビュート(属性)を使用することで、手動でトレイトの実装を書かなくても、コンパイラが自動でトレイトの実装を生成してくれる。

1.使用方法

以下ではPoint構造体に対して、deriveで指定したトレイトが自動実装される。
println!("{:?}", point)やpoint.clone可能になる。

#[derive(Debug, Clone, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

2.実装してくれるトレイト's

厳選致します。

2-1.Debug

構造体の中身が見れる。これがないとコンパイラエラーで中身が確認できない。

println!("{:?}", point) // {:?},{:#?}の2種類表示方法があるヨ

2-2.Default

それぞれの型のdefault()を返してくれる。
例えばStringString::new()を返してくれる。

#[derive(Default, Debug)]
struct Example {
    name: String,
    age: i32,
}

fn main() {
    let x: Example = Default::default();
    println!("{:?}", x);
    // 出力: Example { name: "", age: 0 }
}
  • 好きなデフォルト値を定義したい場合
    手動でDefaultトレイトを呼び出して構造体に定義する。
#[derive(Debug)]
struct Example {
    name: String,
    age: i32,
}

impl Default for Example {
    fn default() -> Self {
        Self {
        name: "aaa".to_string(),
        age: 15,
        }
    }
}

fn main() {
    let x: Example = Default::default();
    println!("{:?}", x);
    // 出力: Example { name: "aaa", age: 15 }
}

2-3.Serde

データのシリアライゼーションとデシリアライゼーション。
serialize + deserializeでser + de、合わせてserde、だそうです。
Rustの構造体等のデータをJSONやTOML,YAML等のフォーマットと相互変換できる。
シリアライズ:構造体 → JSON文字列
デシリアライズ:JSON文字列 → 構造体

使用例

use serde::{Serialize, Deserialize};

// 構造体を定義し、SerializeとDeserializeトレイトを導出
#[derive(Serialize, Deserialize, Debug)]
struct User {
    id: u32,
    name: String,
}

fn main() -> Result<(), serde_json::Error> {
    // インスタンス作成
    let user = User {
        id: 1,
        name: String::from("Alice"),
    };

    // シリアライズ
    let serialized = serde_json::to_string(&user)?;
    println!("Serialized: {}", serialized);
    // 出力: { "id": "1", "name": "Alice"}

    // デシリアライズ
    let deserialized: User = serde_json::from_str(&serialized)?;
    println!("Deserialized: {:?}", deserialized);
    // 出力: User {id: 1, name: "Alice"}
    Ok(())
}
  • Option
    フィールドが省略可能な場合にOption型を使用できる。
#[derive(Serialize, Deserialize, Debug)]
struct User {
    id: u32,
    name: Option<String>,
}

fn main() -> Result<(), serde_json::Error> {
    let json = r#"{"id": "1"}"#; // json形式
    let user:User = serde_json::from_str(json)?; // デシリアライズ
    println!("{:?}", user); // 出力: User {id: 1, name:None}
    Ok(())
}

フィールド名の変更
シリアライズ時(Json形式の時)の名前を指定できる。

#[derive(Serialize, Deserialize, Debug)]
struct User {
    id: u32,
    #[serde(rename = "fullName")]
    name: Option<String>,
}

デフォルト値の設定
デシリアライズ時に、フィールドに値がなかった場合のデフォルト値を設定できる。
#[serde(default)]を構造体定義の上に置くか、フィールドの上に置くかで動作が変わってきます。

a.構造体の上に置く場合
Defaultトレイトを実装し、全てのフィールドのデフォルト値を指定する必要がある。
impl Default for 〇〇(構造体)のように実装する。

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
struct Example {
    id: u32,
    name: Option<String>,
    value: String,
}

impl Default for Example {
    fn default() -> Self {
        Self {
            id: 11,
            name: None,
            value: "test".to_owned(), // .to_string()ではだめでした。
        }
    }
}

fn main() -> Result<(), serde_json::Error> {
    let json = r#"{}"#;
    let example: Example = serde_json::from_str(json)?;
    println!("{:?}", example);
    Ok(())
    // 出力: Example {id: 11, name: None, value: "test" )
}

b.フィールドの上に置く場合
フィールドごとに#[serde(default)]を置く必要がある。
構造体の上に置く場合と違って、Defaultトレイトの実装しなくていい。
それぞれの型のdefaultメソッドが呼び出される。

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Example {
    #[serde(default)]
    id: u32, // u32::default() -> 0
    #[serde(default)]
    name: Option<String>, // Option::default() -> None
    #[serde(default)]
    value: String, // String::default() -> ""
}

fn main() -> Result<(), serde_json::Error> {
    let json = r#"{}"#;
    let example: Example = serde_json::from_str(json)?;
    println!("{:?}", example);
    Ok(())
    // 出力: Example {id: 1, name: None, value: "")
}

引用:https://zenn.dev/sileader/articles/c16929968e00e9

Discussion