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 2:型システムを用いて共通の挙動を表現しよう

Last updated at Posted at 2025-01-02

はじめに

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

他の連載記事 (詳細)

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

今日の内容

概要

共通の挙動を型システムで表現できるようにしましょう。

メソッドのシグネチャで関数の挙動を説明しよう

問(リンク)

enumimplで関数を定義することで、データ構造に関連したメソッドを作成しましょう。

コード (詳細)
enum Item {
    Apple(u32), // 価格
    Meat(u32),  // 価格
}

impl Item {
    // TODO: Itemの価格を返却するメソッドを書いてください。
    fn price(&self) -> u32 {}

    // TODO: Itemの価格を変更するメソッドを書いてください。
    fn increase_price(&mut self, amount: u32) {}

    // TODO: 「Consumed {apple or meat} worth {} yen」という出力をするメソッドを書いてください。
    fn consume(self) {}
}

fn main() {
    let mut apple = Item::Apple(300);
    let meat = Item::Meat(1200);

    // 参照メソッドの呼び出し
    println!("Apple price: {} yen", apple.price());

    // 可変参照メソッドの呼び出し
    apple.increase_price(100);
    println!("Increased apple price: {} yen", apple.price());

    // 所有権を消費するメソッドの呼び出し
    meat.consume();
}

解答(リンク)

関数のシグネチャ部分により、どんなメソッドなのかを分かりやすく表現できます。

  • 参照を取るメソッド(データの構造を取得するが、変更はしないことがシグネチャから分かる)
  • 可変参照を取るメソッド(データを変更する可能性がある)
  • 所有権を消費するメソッド(データを消費する、それ以降でデータを利用しない)
コード (詳細)
enum Item {
    Apple(u32), // 価格
    Meat(u32),  // 価格
}

impl Item {
    // 参照を取るメソッド(データの構造を取得するが、変更はしないことがシグネチャから分かる)
    fn price(&self) -> u32 {
        match self {
            Item::Apple(price) => *price,
            Item::Meat(price) => *price,
        }
    }

    // 可変参照を取るメソッド(データを変更する可能性がある)
    fn increase_price(&mut self, amount: u32) {
        match self {
            Item::Apple(price) => *price += amount,
            Item::Meat(price) => *price += amount,
        }
    }

    // 所有権を消費するメソッド(データを消費する)
    fn consume(self) {
        match self {
            Item::Apple(price) => println!("Consumed apple worth {} yen", price),
            Item::Meat(price) => println!("Consumed meat worth {} yen", price),
        }
    }
}

fn main() {
    let mut apple = Item::Apple(300);
    let meat = Item::Meat(1200);

    // 参照メソッドの呼び出し
    println!("Apple price: {} yen", apple.price());

    // 可変参照メソッドの呼び出し
    apple.increase_price(100);
    println!("Increased apple price: {} yen", apple.price());

    // 所有権を消費するメソッドの呼び出し
    meat.consume();
}

関数ポインタを使いこなそう

問(リンク)

add関数をfp1fp2に関数ポインタとして定義しましょう。

コード (詳細)
fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    // TODO: fp1とfp2に関数ポインタを適用してください。
    let fp1 = add;
    let fp2 = add;

    assert!(fp1 == fp2, "{:?} != {:?}", fp1, fp2);
}

解答(リンク)

let op:のように明示的に関数ポインタを定義してから、代入しましょう。

コード (詳細)
fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    let op: fn(i32, i32) -> i32 = add; // 関数ポインタとして利用するためには明示的なfn型に変換が必要
    let fp1 = op;
    let fp2 = op;

    assert!(fp1 == fp2, "{:?} != {:?}", fp1, fp2);
}

クロージャーを使って環境中の変数を活用しましょう

問(リンク)

環境中のacdivide_and_addに活用できるようにしましょう。

コード (詳細)
fn main() {
    let a = 10;
    let c = 5;

    // TODO: クロージャーとしてdivide_and_addを導入することでコンパイルエラーを解消してください。
    fn divide_and_add(b: i32) -> i32 {
        if b != 0 {
            a / b + c
        } else {
            c
        }
    }

    println!("Divide: {}", divide_and_add(1));
    println!("Divide: {}", divide_and_add(0));
}

解答(リンク)

クロージャーを使うことで環境中の変数を利用することができます。

コード (詳細)
fn main() {
    let a = 10;
    let c = 5;
    let divide_and_add = |b: i32| if b != 0 { a / b + c } else { c }; // クロージャーで定義することで、環境にある変数(a, c)を使った関数にすることができる。

    println!("Divide: {}", divide_and_add(1));
    println!("Divide: {}", divide_and_add(0));
}

さいごに

もしも本リポジトリで不備などあれば、リポジトリの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?