2023/09/29
はじめに
Rustで構造体のフィールドは、インスタンス生成時に、すべてのフィールドを明示的に指定する必要がある。
それはRustの安全性や明示性を重視する姿勢と言え、基本的には望ましい設計である。
しかし、大量のフィールドを持つ構造体のインスタンス生成時に毎回全てのフィールドを明示的に書くのは冗長になることがある。特にデフォルト値を持たせたい場合や意識しないでいいフィールドを提供する際には問題になる。
その際に用いられるのが、Builderパターンであるが、その実装もフィールドが大量となるとそれにつれて増大する。
しかし、そんな悩みを解決するクレートがいくつか存在するので、自分がよく使う typed-builder
を紹介する。
使い方
依存クレートの追記
Cargo.toml
に以下の行を追加する。
最新バージョンはcrates.ioのtyped-builderページを見ると載っている。
typed-builder = "0.16"
構造体への設定
構造体定義の上につけるderive
に、TypedBuilder
も加える。
#[derive(Debug, TypedBuilder)]
struct Person {
age: u8,
name: String,
profile: Option<String>,
interests: Vec<String>,
}
この設定では、以下のように利用することができる。
たった一行いじっただけで、このように簡単にBuilderを実装することが可能となった。
fn main() {
let me = Person::builder()
.name("ysuzuki19".into())
.age(1)
.profile(None)
.interests(vec![])
.build();
println!("{:?}", me);
}
高度な設定
上の利用方法だと、OptionフィールドもメソッドでNone
をセットする必要があるし、値を割り当てる場合はSome()
が必要になる。しかし、それは冗長と言えよう。
そこで、各フィールドの設定をいじってみる。
#[derive(Debug, TypedBuilder)]
struct Person {
#[builder(default = 20)]
age: u8,
#[builder(default, setter(into))]
name: String,
#[builder(default, setter(strip_option, into))]
profile: Option<String>,
#[builder(default_code = "vec![\"Rust\".into()]")]
interests: Vec<String>,
}
これを利用する場合、以下のようにできる。
fn main() {
let me = Person::builder()
.name("ysuzuki19")
.profile("Hello, world!")
.build();
println!("{:?}", me);
}
各設定の説明
まず#[builder()]
でフィールドの振る舞いを設定することができる。
default
default
によって、フィールドのデフォルト値を設定できる。
これにより、.age()
は呼び出さなくても.build()
できるようになる。
#[builder(default = 20)]
age: u8,
この例ではdefault = 20
としているが、単にdefault
とすればその型のデフォルト値になる。
setter(into)
setter(into)
によって、.into()
を省略できるようになる。
これにより、.name("ysuzuki19")
と書けるようになる。
#[builder(default, setter(into))]
name: String,
setter(strip_option)
setter(strip_option)
によって、Some()
を省略する。
これにより、.profile("Hello World!")
とできるようになる。
#[builder(default, setter(strip_option, into))]
profile: Option<String>,
default_code
デフォルト値をコードで設定できる。
これにより、.interests()
を呼び出さない限りはRustだけ興味がある事になる。
#[builder(default_code = "vec![\"Rust\".into()]")]
interests: Vec<String>,
おわりに
以上の設定項目が、よく使う項目です。 マクロで自動実装してくれるのは非常に便利でいいですね!