Rustにおけるオブジェクト指向の考え方

# トレイト
Rustにクラスやプロトタイプチェーンは存在しない。そのかわり、トレイトを使ってオブジェクト指向プログラミングを実現する。トレイトはメソッドを集めたものだ。トレイトを型に実装することによって、その型の値がメソッドを提供するようになる。

## トレイトの定義

`say_hello`メソッドを提供する`SayHello`トレイトを作ってみよう。

```rust
trait SayHello : std::fmt::Display {
    fn say_hello(&self) {
        println!("Hello. This is {}.", self);
    }
}
```

`std::fmt::Display`とは何かというと、これもトレイトだ。`SayHello : std::fmt::Display`というのは、`SayHello`トレイトを実装するには、まず`std::fmt::Display`トレイトを実装する必要があるということを表している。これは、整形表示するのに必要なトレイトだ。

`say_hello`メソッドの第一引数は`&self`となっている。これは、レシーバーへのリファレンスを受け取ることを表している。`say_hello`メソッドにはデフォルトの実装が定義されている。デフォルトの実装は必ずしも定義されなくても良いが、その場合は、型にトレイトを実装する際に定義する必要がある。

## トレイトの実装

`impl`を使って、型にトレイトを実装できる。

```rust
impl SayHello for i32 {}
impl SayHello for str {
    fn say_hello(&self) {
        println!("Hi. I'm {}.", self);
    }
}
```

`str`型については、デフォルトと異なる実装を定義している。

使ってみる。

```rust
trait SayHello : std::fmt::Display {
    fn say_hello(&self) {
        println!("Hello. This is {}.", self);
    }
}

impl SayHello for i32 {}
impl SayHello for str {
    fn say_hello(&self) {
        println!("Hi. I'm {}.", self);
    }
}

fn main() {
    42.say_hello();
    "Alice".say_hello();
}
```

```
Hello. This is 42.
Hi. I'm Alice.
```

# トレイト制約

ジェネリックの型変数がトレイトを実装していることを表したいときは、トレイト制約を使う。

```rust
fn greeting<T: SayHello>(x: T) {
    x.say_hello();
}
```

`<T: SayHello>`の部分が、型変数`T`は`SayHello`を実装していることを表す。

`+`で、型が複数のトレイトを実装していることを表すことができる。

```rust
fn greeting<T: SayHello + SayGoodbye>(x: T) {
    x.say_hello();
    x.say_goodbye();
}
```

`where`節を使った書き方もできる。

```rust
fn greeting<T>(x: T) where T: SayHello + SayGoodbye {
    x.say_hello();
    x.say_goodbye();
}
```

# Uniform Function Call Syntax

メソッドは関数として使うこともできる。

```rust
fn greeting<T>(x: T) where T: SayHello + SayGoodbye {
    <T as SayHello>::say_hello(&x);
    <T as SayGoodbye>::say_goodbye(&x);
}
```

`<T as R>::method(args)`という書き方は、型`T`が実装しているトレイト`R`のメソッド`method`を関数として書いたものだ。このような記法(UFCS)は、複数のトレイトが同名のメソッドを提供していた場合に、曖昧さを無くすために使うことが出来る。

# `Sized`トレイト

`Sized`は特別なトレイトで、`str`や後述のオブジェクト型のような、型からサイズが決定できない型**以外**が実装しており、暗黙のうちに型変数の型制約として加わっている。型変数が`str`やトレイト型を取ることができるようにするためには、この型制約を取り除かなければならない。そのための記法が`?Sized`だ。

リファレンス型に対してSayHelloメソッドを実装する。

```rust
impl<'a, T: ?Sized + SayHello> SayHello for &'a T {
    fn say_hello(&self) {
        <T as SayHello>::say_hello(self);
    }
}
```

このように定義することで、`&str`型も`SayHello`トレイトを実装していることになる。

# トレイトオブジェクト

トレイトオブジェクトは、仮想メソッドテーブル(vtable)を使った動的ディスパッチができる型だ。トレイト`R`を実装した型`T`へのリファレンス`&T`や`Box<T>`を`&R`あるいは`Box<R>`にキャストすることで、トレイトオブジェクトに変換できる。

```rust
Box::new(42) as Box<SayHello>
```

異なる型のデータも、トレイトオブジェクトに変換することで同じコンテナーに入れられるようになる。

```rust
trait SayHello : std::fmt::Display {
    fn say_hello(&self) {
        println!("Hello. This is {}.", self);
    }
}

impl SayHello for i32 {}
impl SayHello for str {
    fn say_hello(&self) {
        println!("Hi. I'm {}.", self);
    }
}
impl<'a, T: ?Sized + SayHello> SayHello for &'a T {
    fn say_hello(&self) {
        <T as SayHello>::say_hello(self);
    }
}

fn main() {
    let v = vec![
        Box::new(42) as Box<SayHello>,
        Box::new("Alice") as Box<SayHello>,
    ];
    for x in &v {
        x.say_hello();
    }
}
```

**[オブジェクト安全](https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md)なトレイトについてのみトレイトオブジェクトに変換できる。**バイナリメソッド（レシーバー以外の引数にSelf型の値をとるメソッド）を持つトレイトなどは、オブジェクト安全でないので、トレイトオブジェクトに変換できない。

```rust
fn main() {
    let _ = Box::new(42) as Box<std::cmp::Eq>; // ERROR
}
```

オブジェクト安全の詳しい定義は[オブジェクト安全#Detailed design](https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md#detailed-design)を参照すること。