Rust 100 Ex 🏃【11/37】 Sized トレイト・From トレイト・関連型 ～おもしろトレイトと関連型～

前の記事

- [【0】 準備](https://qiita.com/namn1125/items/bd1b4cd028874189a3c1) ← 初回
- ...
- [【10】 トレイト境界・文字列・Derefトレイト ～トレイトのアレコレ～](https://qiita.com/namn1125/items/9060faee2965f23e0e3d) ← 前回
- 【11】 Sized トレイト・From トレイト・関連型 ～おもしろトレイトと関連型～ ← 今回

<details><summary>全記事一覧</summary>

- [【0】 準備](https://qiita.com/namn1125/items/bd1b4cd028874189a3c1)
- [【1】 構文・整数・変数](https://qiita.com/namn1125/items/c776768baec89b8a0438)
- [【2】 if・パニック・演習](https://qiita.com/namn1125/items/13870965e8273bc87bce)
- [【3】 可変・ループ・オーバーフロー](https://qiita.com/namn1125/items/4f57f8aede2f5201016f)
- [【4】 キャスト・構造体 (たまにUFCS)](https://qiita.com/namn1125/items/227ed5bbedbb775c5d27)
- [【5】 バリデーション・モジュールの公開範囲 ～ → カプセル化！～](https://qiita.com/namn1125/items/46721cceccbfa9ec3c7a)
- [【6】 カプセル化の続きと所有権とセッター ～そして不変参照と可変参照！～](https://qiita.com/namn1125/items/442de7798d49f777384c)
- [【7】 スタック・ヒープと参照のサイズ ～メモリの話～](https://qiita.com/namn1125/items/780d80e4340f0e34dbf6)
- [【8】 デストラクタ(変数の終わり)・トレイト ～終わりと始まり～](https://qiita.com/namn1125/items/7247edde3b6bd0b85b25)
- [【9】 Orphan rule (孤児ルール)・演算子オーバーロード・derive ～Empowerment 💪 ～](https://qiita.com/namn1125/items/e565713b423301a80c76)
- [【10】 トレイト境界・文字列・Derefトレイト ～トレイトのアレコレ～](https://qiita.com/namn1125/items/9060faee2965f23e0e3d)
- [【11】 Sized トレイト・From トレイト・関連型 ～おもしろトレイトと関連型～](https://qiita.com/namn1125/items/b68990712d379a3d6a49)
- [【12】 Clone・Copy・Dropトレイト ～覚えるべき主要トレイトたち～](https://qiita.com/namn1125/items/c6f34945f331c7229746)
- [【13】 トレイトまとめ・列挙型・match式 ～最強のトレイトの次は、最強の列挙型～](https://qiita.com/namn1125/items/6b2cc31d6a47f9ffaff6)
- [【14】 フィールド付き列挙型とOption型 ～チョクワガタ～](https://qiita.com/namn1125/items/6fe69d1cab6c7936c698)
- [【15】 Result型 ～Rust流エラーハンドリング術～](https://qiita.com/namn1125/items/698aafaf22ec4bfd1bde)
- [【16】 Errorトレイトと外部クレート ～依存はCargo.tomlに全部お任せ！～](https://qiita.com/namn1125/items/9dae7b728fa0668e4102)
- [【17】 thiserror・TryFrom ～トレイトもResultも自由自在！～](https://qiita.com/namn1125/items/d67006a29b7ff5d6148c)
- [【18】 Errorのネスト・慣例的な書き方 ～Rustらしさの目醒め～](https://qiita.com/namn1125/items/705829027661a38e4a4f)
- [【19】 配列・動的配列 ～スタックが使われる配列と、ヒープに保存できる動的配列～](https://qiita.com/namn1125/items/9c49fd4c08f3e61896c7)
- [【20】 動的配列のリサイズ・イテレータ ～またまたトレイト登場！～](https://qiita.com/namn1125/items/6e4dede789c6de97f396)
- [【21】 イテレータ・ライフタイム ～ライフタイム注釈ようやく登場！～](https://qiita.com/namn1125/items/9a1224abf733f29a980a)
- [【22】 コンビネータ・RPIT ～ :dragon: 「 `Iterator` トレイトを実装してるやつ」～](https://qiita.com/namn1125/items/27fe20f2d60803c94357)
- [【23】 `impl Trait` ・スライス ～配列の欠片～](https://qiita.com/namn1125/items/7601d0268293ce7fcf28)
- [【24】 可変スライス・下書き構造体 ～構造体で状態表現～](https://qiita.com/namn1125/items/a9acc7dc2ca7c4c55cc3)
- [【25】 インデックス・可変インデックス ～インデックスもトレイト！～](https://qiita.com/namn1125/items/bd43375362af10ea8b42)
- [【26】 HashMap・順序・BTreeMap ～Rustの辞書型～](https://qiita.com/namn1125/items/a2806cded12fa719a1cb)
- [【27】 スレッド・'staticライフタイム ～並列処理に見るRustの恩恵～](https://qiita.com/namn1125/items/5a4a09172834063268b1)
- [【28】 リーク・スコープ付きスレッド ～ライフタイムに技あり！～](https://qiita.com/namn1125/items/34a0aacd4d40f9234aef)
- [【29】 チャネル・参照の内部可変性 ～Rustの虎の子、mpscと `Rc<RefCell<T>>`～](https://qiita.com/namn1125/items/861e72dbb4b837508948)
- [【30】 双方向通信・リファクタリング ～返信用封筒を入れよう！～](https://qiita.com/namn1125/items/46f03de967d0de46737e)
- [【31】 上限付きチャネル・PATCH機能 ～パンクしないように制御！～](https://qiita.com/namn1125/items/d7ae8a205ee969339401)
- [【32】 `Send`・排他的ロック(`Mutex`)・非対称排他的ロック(`RwLock`) ～真打 `Arc<Mutex<T>>` 登場～](https://qiita.com/namn1125/items/eee890dc8672e975e70c)
- [【33】 チャネルなしで実装・Syncの話 ～考察回です～](https://qiita.com/namn1125/items/cc8bee3871b727e564e3)
- [【34】 `async fn`・非同期タスク生成 ～Rustの非同期入門～](https://qiita.com/namn1125/items/9c32b730a283ad76c891)
- [【35】 非同期ランタイム・Futureトレイト ～非同期のお作法～](https://qiita.com/namn1125/items/c840d48f8f558613ec10)
- [【36】 ブロッキング・非同期用の実装・キャンセル ～ラストスパート！～](https://qiita.com/namn1125/items/39c139da3f1f26264353)
- [【37】 Axumでクラサバ！ ～最終回～](https://qiita.com/namn1125/items/bae492f823fbe60e9974)
- [【おまけ1】 Rustで勘違いしていたこと3選 🏄🌴 【100 Exercises To Learn Rust 🦀 完走記事 🏃】](https://qiita.com/namn1125/items/2a59f486cce30fd2b889)
- [【おまけ2】 【🙇 懺悔 🙇】Qiitanグッズ欲しさに1日に33記事投稿した話またはQiita CLIとcargo scriptを布教する的な何か](https://qiita.com/namn1125/items/8e552694b389c5b13b5e)
</details>

[100 Exercise To Learn Rust](https://rust-exercises.com/) 演習第11回になります！今回は演習中心に軽めに済ませたかったのですが、まぁそうも言ってられなさそうですね。無理せず行きます！

今回の関連ページ

- [4.8. Sized trait](https://rust-exercises.com/04_traits/08_sized)
- [4.9. From trait](https://rust-exercises.com/04_traits/09_from)
- [4.10. Associated vs generic types](https://rust-exercises.com/04_traits/10_assoc_vs_generic)

# [[04_traits/08_sized](https://github.com/mainmatter/100-exercises-to-learn-rust/blob/main/exercises/04_traits/08_sized/src/lib.rs)] Sized トレイト

- [4.8. Sized trait](https://rust-exercises.com/04_traits/08_sized)

問題はこちらです。今回はたまにある「コンパイルエラーが出ることを確かめたら次のエクササイズに進んでいいよ」問題のようです。

```rust:lib.rs
pub fn example() {
    // Trying to get the size of a str (or any other DST)
    // via `std::mem::size_of` will result in a compile-time error.
    //
    // TODO: Comment out the following line and move on to the next exercise.
    std::mem::size_of::<str>();
}
```

## 解説

「 `&str` や `&[T]` は見るのに `str` や `[T]` を直接扱っているものは見ないな？」という疑問に関するアンサーが[今回のBookの内容](https://rust-exercises.com/04_traits/08_sized)です。

Rustでは、「コンパイル時にメモリ上のサイズが決まるもの」に `Sized` という **マーカートレイト** を、逆に「コンパイル時にメモリ上のサイズ不定なもの(Dynamically Sized Type, DST)」に `!Sized` というマーカートレイトを付けます。

「マーカートレイト」というのは、特定のメソッド等は持たないものの、 **対象の型の性質を表すのに使うトレイト** です。この他にも `Copy` 、 `Sync` 、 `Send` 等々色々あります。

DSTな、つまり `!Sized` な型には `str` や `[T]` の他に、 トレイトオブジェクト `dyn Trait` ([第18回](https://qiita.com/namn1125/items/705829027661a38e4a4f)等で取り扱い)があります。彼らはコンパイル時サイズ不定なので、 `size_of` 関数のジェネリクスに渡すと(`func::<T>()`みたいに[turbofish `::<>`](https://keens.github.io/blog/2019/12/03/rustnoturbofishworikaisuru/) を使って渡しています。)エラーになってしまいます。ちなみに `size_of` に限らず全ての関数はデフォルトでジェネリクス型に `Sized` を要求してきます。 サイズ不定なやつを渡したい場合 `?Sized` をトレイト境界に書く必要があります。

問題に戻りましょう。せっかくなのでコンパイルが通る例を記載しておきます。

```rust:lib.rs
pub fn example() {
    // std::mem::size_of::<str>();
    // std::mem::size_of::<[usize]>();

    // 次はコンパイルが通る
    std::mem::size_of::<&str>();
    std::mem::size_of::<&[usize]>();
    std::mem::size_of::<[usize; 3]>();
}
```

DST自体は `?Sized` でも、 **DSTの参照は `Sized`** で、その大きさは普通の参照なら `usize` と同様(64bit OSなら8バイト)になっています。なので上記コードはコンパイルが通ります。

# [[04_traits/09_from](https://github.com/mainmatter/100-exercises-to-learn-rust/blob/main/exercises/04_traits/09_from/src/lib.rs)] From トレイト

- [4.9. From trait](https://rust-exercises.com/04_traits/09_from)

問題はこちらです。[第9回のOrphan rule](https://qiita.com/namn1125/items/e565713b423301a80c76)にてコンパイルを通すために使用したニュータイプパターン(ラッパー)が本問題でも使われていますね。

```rust:lib.rs
// TODO: Implement the `From` trait for the `WrappingU32` type to make `example` compile.

pub struct WrappingU32 {
    value: u32,
}

fn example() {
    let wrapping: WrappingU32 = 42.into();
    let wrapping = WrappingU32::from(42);
}
```

`u32` -> `WrappingU32` というキャストを手軽に行えるようにするために、 `impl From<u32> for WrappingU32` してほしいということらしいです。

Rustではキャストもトレイトで実現されている[^primitive_cast]わけです！

[^primitive_cast]: もちろんですが、`as` を使用したプリミティブ型のキャストのことではなく、このキャストにはトレイトが関わっていません(確か)。しかし使用頻度は `from/into` または `try_from/try_into` の方が多いんじゃないかなと思います。

## 解説

実装すればよいのです。

```rust:lib.rs
impl From<u32> for WrappingU32 {
    fn from(value: u32) -> Self {
        Self { value }
    }
}
```

ちなみに `impl From<T> for U` の方を実装すると `impl Into<U> for T` も自動実装されます。こういう関係にあるものをDual Trait (双子トレイト...？) というらしい、便利ですね。

[Bookに書いてある](https://rust-exercises.com/04_traits/09_from)ように、Dual Traitの実装自体は難しくないので、試しに何か書いてみると面白いかもしれません。

```rust:Rust
trait MyFrom<T> {
    fn my_from(value: T) -> Self;
}

trait MyInto<U> {
    fn my_into(self) -> U;
}

// Dual Traitたらしめている部分
impl<T, U> MyInto<U> for T
where
    U: MyFrom<T>
{
    fn my_into(self) -> U {
        U::my_from(self)
    }
}

// 意味としては、「型Tに対して、MyFrom<T>を実装しているUについてMyInto<U>を実装する」
```

# [[04_traits/10_assoc_vs_generic](https://github.com/mainmatter/100-exercises-to-learn-rust/blob/main/exercises/04_traits/10_assoc_vs_generic/src/lib.rs)] 

- [4.10. Associated vs generic types](https://rust-exercises.com/04_traits/10_assoc_vs_generic)

問題はこちらです。なんか[Book](https://rust-exercises.com/04_traits/10_assoc_vs_generic)にめっちゃ良いこと書いてるのにそっちをあんまり意識してない問題...？！

```rust:lib.rs
// TODO: Define a new trait, `Power`, that has a method `power` that raises `self`
//  to the power of `n`.
//  The trait definition and its implementations should be enough to get
//  the tests to compile and pass.
//
// Recommendation: you may be tempted to write a generic implementation to handle
// all cases at once. However, this is fairly complicated and requires the use of
// additional crates (i.e. `num-traits`).
// Even then, it might be preferable to use a simple macro instead to avoid
// the complexity of a highly generic implementation. Check out the
// "Little book of Rust macros" (https://veykril.github.io/tlborm/) if you're
// interested in learning more about it.
// You don't have to though: it's perfectly okay to write three separate
// implementations manually. Venture further only if you're curious.

#[cfg(test)]
mod tests {
    use super::Power;

    #[test]
    fn test_power_u16() {
        let x: u32 = 2_u32.power(3u16);
        assert_eq!(x, 8);
    }

    #[test]
    fn test_power_u32() {
        let x: u32 = 2_u32.power(3u32);
        assert_eq!(x, 8);
    }

    #[test]
    fn test_power_ref_u32() {
        let x: u32 = 2_u32.power(&3u32);
        assert_eq!(x, 8);
    }
}
```

累乗のトレイト `Power` 💪 を実装してほしいという問題ですね。 `num-traits` やマクロを使ったほうが良さそうというアドバイス付きです。

## 解説

というわけで [`num::Num`](https://docs.rs/num/latest/num/trait.Num.html) トレイトとマクロ両方を使って実装してみました。

```rust:lib.rs
use num::Num;
use std::collections::HashMap;
use std::hash::Hash;

fn power_inner<N>(n: N, e: u32) -> N
where
    N: Num + Hash + Eq + Clone + Copy + std::fmt::Debug,
{
    if e == 0 {
        return N::one();
    }

    if e == 1 {
        return n;
    }

    let vv = power_inner(n, e / 2);

    let v = vv * vv * if e % 2 == 0 { N::one() } else { n };

    v
}

trait Power<RHS = Self>: Num + Hash + Eq + Clone + Copy {
    fn power(self, rhs: RHS) -> Self;
}

macro_rules! power_impl {
    ( $(($t:ty, $r:ty))* ) => {$(
        impl Power<$r> for $t {
            fn power(self, rhs: $r) -> Self {
                power_inner(self, rhs.clone().into())
            }
        }
    )*}
}

power_impl!((u32, u32)(u32, u16)(u32, &u32)(u128, u32));
```

マクロを使う場合トレイト側のトレイト境界は不要ですが、試行錯誤の結果残していました。まぁあるとマクロのシグネチャを見た人に親切かなと思い残しています。

演習問題とは関係なく、[Book](https://rust-exercises.com/04_traits/10_assoc_vs_generic)の方では「ジェネリクス」と「関連型」どちらを使うべき？という話題が繰り広げられています。本記事でもその指針に触れたら今回を終わりたいと思います。

> Conclusion
> To recap:
> 
> - Use an associated type when the type must be uniquely determined for a given trait implementation.
> - Use a generic parameter when you want to allow multiple implementations of the trait for the same type, with different input types.

とあります。筆者は以下のように捉えています。

- トレイトの自身の型以外の型指定は引数のような身分: ジェネリクスを使うべきシーン。 `impl Power<U> for T` は、 `T × U -> 実装` という写像と捉えられる。
- トレイトの自身の型以外の型は、トレイトの実装により決まる、つまり返り値のような身分: 関連型を使うべきシーン。 `impl Deref for T` とした時、 型 `Target = U` が一意に定まるべき

ジェネリクスと関連型は別に混在していてもよくて、その場合は上記の指針で考えれば良いんじゃないかなと思っています。

では次の問題に行きましょう！

次の記事: [【12】 Clone・Copy・Dropトレイト ～覚えるべき主要トレイトたち～](https://qiita.com/namn1125/items/c6f34945f331c7229746)