やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Rustのトレイト

 C#Javaでいうインタフェースに類似した機能。

成果物

トレイト

定義

pub trait Summary {
    fn summarize(&self) -> String;
}

 traitキーワードを使って定義する。

実装

 トレイトを型に実装する。

pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}
impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

 impl トレイト名 for 型名とする。型はstruct, enumなど。

コヒーレンス(オーファンルール)

 トレイトには制約が1つある。

トレイトか対象の型が自分のクレートに固有(local)であるときのみ、型に対して実装できる

 コードを保つために。

この規則により、他の人のコードが自分のコードを壊したり、 その逆が起きないことを保証してくれます。この規則がなければ、2つのクレートが同じ型に対して同じトレイトを実装できてしまい、 コンパイラはどちらの実装を使うべきかわからなくなってしまうでしょう。

デフォルト実装

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}

 実装がオーバーライドされたら呼び出せなくなる。

空実装の呼出

pub trait Summary {
    fn summarize_author(&self) -> String;
    fn summarize(&self) -> String {
        format!("(Read more from {}...)", self.summarize_author())
    }
}
impl Summary for NewsArticle {
    fn summarize_author(&self) -> String { format!("{}", self.author) }
}

トレイト境界

 ジェネリックな型のうち、特定の型をもつものだけに限定する。

pub fn notify<T: Summary>(item: T) {
    println!("Breaking news! {}", item.summarize());
}

 複数のトレイト境界を指定できる。

+記法

fn some_fn<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {}

where記法

fn some_fn<T, U>(t: T, u: U) -> i32 
    where T: Display + Clone,
          U: Clone + Debug
{}

ブランケット実装(blanket implementation)

 Displayトレイトを実装するあらゆる型にToStringトレイトを実装するときは以下。

impl<T: Display> ToString for T {}
let s = 3.to_string();

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux

前回まで