0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Effective-Rustlings-jp】Day 7:複雑な型にはビルダを使おう

Last updated at Posted at 2025-01-07

はじめに

こんにちは。細々とプログラミングをしているsotanengelです。
この記事は以下の記事の連載です。

他の連載記事 (詳細)

また本記事はEffective Rust(David Drysdale (著), 中田 秀基 (翻訳))を参考に作成されております。とてもいい書籍ですので興味を持った方は、ぜひ読んでみてください!

今日の内容

概要

Rustで構造体のインスタンスを作成するためには「全てのインスタンスを指定する」必要があります。
そのため愚直にコードを書いてしまうと、構造体の修正時に変更箇所が多岐に渡ってしまいます。
そこでビルダという関数を作り、インスタンスを作成する際にその関数を使うことで変更箇所を最小限に抑えることができます。

ビルダを実装してみよう

問(リンク)

Event構造体に対するEventBuilderというビルダを実装してください。

コード (詳細)
use time::macros::date;
use time::Date;

#[derive(Debug)]
#[allow(dead_code)]
struct Event {
    title: String,
    date: Option<Date>,
    description: Option<String>,
}

// TODO: 「Event構造体そのものをタプル構造体で保持する」EventBuilderという名前のビルダを作成してください。

impl EventBuilder {
    // TODO: titleを入力するとEventBuilderを返すnew関数を実装してください。
    fn new(title: &str) -> Self {}

    // TODO: dateを入力するとEventBuilderに「日付情報」を追加するメソッドを実装してください。
    fn date(mut self, date: Date) -> Self {}

    // TODO: descriptionを入力するとEventBuilderに「イベント詳細情報」を追加するメソッドを実装してください。
    fn description(mut self, description: &str) -> Self {}

    // TODO: Eventインスタンスを作成するbuildメソッドを実装してください。
    fn build(self) -> Event {}
}

fn main() {
    let event = EventBuilder::new("Rust.Tokyo")
        .date(date!(2024 - 11 - 30)) // ここに日付をセット
        .description("2023年にデジタル戦略の立案・支援・人財育成を担う組織として、デジタル・イノベーション推進部を新設しました。")
        .build();

    println!("{:?}", event);
}

解答(リンク)

この実装の場合はメソッドがSelfを消費するため、dateやdescriptionを同じタイミングで実行する必要があります。

コード (詳細)
use time::macros::date;
use time::Date;

#[derive(Debug)]
#[allow(dead_code)]
struct Event {
    title: String,
    date: Option<Date>,
    description: Option<String>,
}

// ビルダーの実装
struct EventBuilder(Event);

impl EventBuilder {
    fn new(title: &str) -> Self {
        EventBuilder(Event {
            title: title.to_string(),
            date: None,
            description: None,
        })
    }

    fn date(mut self, date: Date) -> Self {
        self.0.date = Some(date);
        self
    }

    fn description(mut self, description: &str) -> Self {
        self.0.description = Some(description.to_string());
        self
    }

    // インスタンスを生成
    fn build(self) -> Event {
        self.0
    }
}

fn main() {
    let event = EventBuilder::new("Rust.Tokyo")
        .date(date!(2024 - 11 - 30)) // ここに日付をセット
        .description("2023年にデジタル戦略の立案・支援・人財育成を担う組織として、デジタル・イノベーション推進部を新設しました。")
        .build();

    println!("{:?}", event);
}

繰り返し使用できるビルダを実装する

問(リンク)

先ほどのコードの一部を修正することでevent_listに同じビルダから同じフィールドを持つインスタンスを格納してください。

コード (詳細)
use time::macros::date;
use time::Date;

#[derive(Debug, Clone)]
#[allow(dead_code)]
struct Event {
    title: String,
    date: Option<Date>,
    description: Option<String>,
}

// ビルダーの実装
struct EventBuilder(Event);

impl EventBuilder {
    fn new(title: &str) -> Self {
        EventBuilder(Event {
            title: title.to_string(),
            date: None,
            description: None,
        })
    }

    // TODO: 段階的にビルダに情報をセットできるように引数と返り値の型を調整してください。
    fn date(mut self, date: Date) -> Self {
        self.0.date = Some(date);
        self
    }

    // TODO: 段階的にビルダに情報をセットできるように引数と返り値の型を調整してください。
    fn description(mut self, description: &str) -> Self {
        self.0.description = Some(description.to_string());
        self
    }

    // TODO: 1つのビルダから複数のインスタンスを作成できるように「引数の型」と「関数内部」を実装してください。
    fn build(self) -> Event {}
}

fn main() {
    let mut event_builder = EventBuilder::new("Rust.Tokyo");

    // 段階的にビルダーに情報をセットする
    event_builder.date(date!(2024 - 11 - 30));
    event_builder.description("2023年にデジタル戦略の立案・支援・人財育成を担う組織として、デジタル・イノベーション推進部を新設しました。");

    // 配列に同じビルダー情報から作ることができるインスタンスを生成する
    let event_list = vec![
        event_builder.build(),
        event_builder.build(),
        event_builder.build(),
    ];

    println!("{:?}", event_list);
}

解答(リンク)

コード参照。

コード (詳細)
use time::macros::date;
use time::Date;

#[derive(Debug, Clone)]
#[allow(dead_code)]
struct Event {
    title: String,
    date: Option<Date>,
    description: Option<String>,
}

// ビルダーの実装
struct EventBuilder(Event);

impl EventBuilder {
    fn new(title: &str) -> Self {
        EventBuilder(Event {
            title: title.to_string(),
            date: None,
            description: None,
        })
    }

    fn date(&mut self, date: Date) -> &mut Self {
        self.0.date = Some(date);
        self
    }

    fn description(&mut self, description: &str) -> &mut Self {
        self.0.description = Some(description.to_string());
        self
    }

    // インスタンスを生成
    fn build(&self) -> Event {
        self.0.clone()
    }
}

fn main() {
    let mut event_builder = EventBuilder::new("Rust.Tokyo");

    // 段階的にビルダーに情報をセットする
    event_builder.date(date!(2024 - 11 - 30));
    event_builder.description("2023年にデジタル戦略の立案・支援・人財育成を担う組織として、デジタル・イノベーション推進部を新設しました。");

    // 配列に同じビルダー情報から作ることができるインスタンスを生成する
    let event_list = vec![
        event_builder.build(),
        event_builder.build(),
        event_builder.build(),
    ];

    println!("{:?}", event_list);
}

さいごに

もしも本リポジトリで不備などあれば、リポジトリのissueやPRなどでご指摘いただければと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?