🐙

Rust | From トレイトで HashMap<K, V> を 型変換する

2024/09/09に公開

はじめに

Rust の From トレイトを使って、複数の構造体などに対して、双方向の型変換を実装するケースは少なくないと思います。(特に責務分けを厳格にしているプロジェクトだと余計にそうではないでしょうか)
私自身、型変換処理に苦労していたところがあり、若干の苦手意識をもっているような気がします。
HashMap<K, V>を使った時に、どのように型変換をしていくかの実装をちょこっとやっていければと思います!

HashMap<K, V> を使った構造体のイメージ

多少無理やりですが、以下のようなHashMap<K, V>の入った構造体を定義しています。
UserAUserBのように型変換を行うためには、From トレイトを実装することが必要です。

struct UsersA {
    profile: HashMap<String, ProfileA>,
}

struct UsersB {
    profile: HashMap<String, ProfileB>,
}

struct ProfileA {
    name: String,
    age: u8,
}

struct ProfileB {
    name: String,
    age: u8,
}

さらに、ProfileAProfileBという構造体も中に実装しているため、HashMap<K, V>の V にあたる部分を展開しつつ型変換処理を行う必要があります。

From トレイトを使った型変換

下記のようにHashMap<K, V>を展開しつつ型変換処理を行うことが可能です。

impl From<ProfileA> for ProfileB {
    fn from(value: ProfileA) -> Self {
        Self {
            name: value.name,
            age: value.age,
        }
    }
}

impl From<UsersA> for UsersB {
    fn from(users: UsersA) -> Self {
        Self {
            profile: users
                .profile
                .into_iter()
                .map(|(key, value)| (key, value.into()))
                .collect(),
        }
    }
}

上記のように、impl From<T> for T として、ProfileAProfileBに変換します。
中でfrom()を作成して、Selfを返すことで ProfileBに変換することができます。

UsersAからUsersBに対しての型変換は、HashMap となっている profileパラメータを into_iter()map()を使って展開するようにしました。
map()の中で、profilevalueinto()を使って上で説明した from()を呼び出しています。

最終的なコード
struct UsersA {
    profile: HashMap<String, ProfileA>,
}

struct UsersB {
    profile: HashMap<String, ProfileB>,
}

impl From<UsersA> for UsersB {
    fn from(users: UsersA) -> Self {
        Self {
            profile: users
                .profile
                .into_iter()
                .map(|(key, value)| (key, value.into()))
                .collect(),
        }
    }
}

struct ProfileA {
    name: String,
    age: u8,
}

struct ProfileB {
    name: String,
    age: u8,
}

impl From<ProfileA> for ProfileB {
    fn from(value: ProfileA) -> Self {
        Self {
            name: value.name,
            age: value.age,
        }
    }
}

おわりに

冒頭でも述べたようにHashMap<K, V>を扱うケースはRustのみならず他の言語でもよく見ると思います。
この機会にしっかりマスターしてRustのHashMapや型を自由自在に操れるようになりたいですね!

では。

コラボスタイル Developers

Discussion