Skip to content

Instantly share code, notes, and snippets.

@qnighy
Last active March 6, 2021 19:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qnighy/e7a833eebd57ef778eaff3a8ab3649d7 to your computer and use it in GitHub Desktop.
Save qnighy/e7a833eebd57ef778eaff3a8ab3649d7 to your computer and use it in GitHub Desktop.
// この方法ならunwrap()もしなくてすむのではなかろうか
#[derive(Debug)]
struct Person {
id: u32,
name: String,
age: u32,
address: Option<String>,
zipcode: Option<String>,
}
// 例えばIdTypeは、未初期化なら(), 初期化済ならu32という型をもつ。
// もし、IdTypeとしてBox<&[u8]>みたいなデタラメな型も入れられるのが
// 嫌なら、Empty/Filledというダミー型と適当なtraitを用意して、
// Empty/Filledに対応するtrait implのassociated typeから型を
// 選択するという仕様にもできそう。
#[derive(Debug)]
struct PersonBuilder<IdType, NameType, AgeType> {
id: IdType,
name: NameType,
age: AgeType,
address: Option<String>,
zipcode: Option<String>,
}
impl PersonBuilder<(), (), ()> {
pub fn new() -> Self {
PersonBuilder {
id: (),
name: (),
age: (),
address: None,
zipcode: None,
}
}
}
// PersonBuilder<u32, String, u32> は実はPersonと同型なんでPersonをtype synonymとする手もある
impl PersonBuilder<u32, String, u32> {
pub fn build(self) -> Person {
Person {
id: self.id,
name: self.name,
age: self.age,
address: self.address,
zipcode: self.zipcode,
}
}
}
// このimpl内で実装するとidなりnameなりは2回以上呼べるけど、ちょうど1回しか呼べない仕様にもできるはず
impl<IdType, NameType, AgeType> PersonBuilder<IdType, NameType, AgeType> {
pub fn id(self, id: u32) -> PersonBuilder<u32, NameType, AgeType> {
PersonBuilder {
id: id,
name: self.name,
age: self.age,
address: self.address,
zipcode: self.zipcode,
}
}
pub fn name<S: Into<String>>(self, name: S) -> PersonBuilder<IdType, String, AgeType> {
PersonBuilder {
id: self.id,
name: name.into(),
age: self.age,
address: self.address,
zipcode: self.zipcode,
}
}
pub fn age(self, age: u32) -> PersonBuilder<IdType, NameType, u32> {
PersonBuilder {
id: self.id,
name: self.name,
age: age,
address: self.address,
zipcode: self.zipcode,
}
}
pub fn address<S: Into<String>>(mut self, address: S) -> Self {
self.address = Some(address.into());
self
}
pub fn zipcode<S: Into<String>>(mut self, zipcode: S) -> Self {
self.zipcode = Some(zipcode.into());
self
}
}
fn main() {
let b = PersonBuilder::new()
.id(123)
.name("hoge")
.age(23)
.address("foo")
.build();
println!("b = {:?}", b);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment