4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

引数でのimpl とジェネリクスの違い

Last updated at Posted at 2020-06-09

はじめに

Rustを勉強中です。この度クリーンアーキテクチャをRustで書こうとしていて、Rustではどう書くのだろうと悩むことが多いです。
処理をインターフェイスのみに依存する書き方について、 impl trait と書くやり方をしったのですが、これはジェネリクスとどう違うのかを調べました。

impl traitを引数や返り値の型指定に使う

まずはimplを引数に使ってある例をあげますね。
今読んでいるコードを少し変えたものです。
メソッドの定義にimplが使われていますね。

#[derive(Debug, Clone, Copy)]
pub struct UserId(pub u32);

#[derive(Debug, Clone)]
pub struct User {
    pub id: UserId,
    pub parent_id: UserId,
    pub text: String,
}

impl User {
// textの引数の指定にimpl traitが使われている
    pub fn new(id: UserId, parent_id: UserId, text: impl Into<String>) -> Self {
        User {
            id,
            parent_id,
            text: text.into(),
        }
    }
}

impl traitとジェネリクスの違い

まず以下のコードは同一です。

# 2つの関数は同じ
fn map<U>(self, f: impl FnOnce(T) -> U) -> Option<U>
fn map<U, F>(self, f: F) -> Option<U> where F: FnOnce(T) -> U

違いがあるとしたら、型を明確に指定できないことだそうです。

fn foo<T: Trait>(t: T)
fn bar(t: impl Trait)

foo::<u32>(0) // OK
bar::<u32>(0) // NG

なので、上記のコードのメソッドの部分はこう書けることになります。


impl User {
    pub fn new<T: Into<String>>(id: UserId, parent_id: UserId, text: T) -> Self {
        User {
            id,
            parent_id,
            text: text.into(),
        }
    }
}

最後に

構文上どちらが読みやすいかはよくわからないですが個人的にはジェネリクスのほうが読みやすい気がします。
何かご指摘があればコメントください。

参考文献

4
2
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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?