はじめに
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(),
}
}
}
最後に
構文上どちらが読みやすいかはよくわからないですが個人的にはジェネリクスのほうが読みやすい気がします。
何かご指摘があればコメントください。