---
# System prepended metadata

title: Rust テキスト学習 5
tags: ['#[attr]', Trait, Rust]

---

###### tags: `Rust` `Trait` `#[attr]`
# Rust テキスト学習 5

# Trait
トレイト = ある型が提供しなければならない機能をRustコンパイラに知らせる言語機能

要するに、他の言語で言うところのinterface機能
structのメソッドの実装の細かい内容を知らなくても
traitに定義されている通りの引数、戻り値を知っていれば
同様に扱える。
いわゆる、ダックタイピングのための機能。


使い方は簡単で、 struct と impl の間に挟むだけ

```rust=
struct Circle {
    x: f64,
    y: f64,
    radius: f64,
}

trait HasArea{
    fn area(&self) -> f64;
}
trait Grow {
    fn grow(&mut self, g: f64);
}
impl HasArea for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }
}
impl Grow for Circle {
    fn grow(&mut self, g: f64){
        self.radius += g;
    }
}


fn main() {
    let mut c = Circle{x: 1.0, y: 2.0, radius: 3.0};
    c.grow(10.0);
    println!("{}", c.area());
}
```
trait ブロックと impl ブロックは似ているように見える。
しかし、traitブロックで定義するのはメソッドの型シグネチャ(識別子)だけ
trait = 取り扱い、使い方の意


イメージとしては、
- trait : メソッドの return と args の型だけ定義
- impl  : 実際の処理を実装

## ジェネリックとトレイト
## ジェネリック関数におけるトレイト境界
Traitを用いるメリットの1つに、
**あるTypeの振る舞いを確約できる**　という物がある

これはジェネリックにおいて役に立つ機能である。
\<T>という型を受け取り、 .area() というメソッドを実行したいとき、
Tはどんな型も取りうるので、 .area() メソッドを実装しているとは限らない。
よってエラーになる。

**\<T: HasArea>** のように、ジェネリックTに HasArea トレイトのラベルをつけることで
HasAreaに定義されるメソッドを実装した型のみを受け取れるようになる。

すなわち、 **ジェネリックパラメータの制限** を追加できるということである。

例.
```rust=
trait HasArea {
    fn area(&self) -> f64;
}

struct Circle {
    x: f64,
    y: f64,
    radius: f64,
}

impl HasArea for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

struct Square {
    x: f64,
    y: f64,
    side: f64,
}

impl HasArea for Square {
    fn area(&self) -> f64 {
        self.side * self.side
    }
}

fn print_area<T: HasArea>(shape: T) {
    println!("This shape has an area of {}", shape.area());
}

fn main() {
    let c = Circle {
        x: 0.0f64,
        y: 0.0f64,
        radius: 1.0f64,
    };

    let s = Square {
        x: 0.0f64,
        y: 0.0f64,
        side: 1.0f64,
    };
    print_area(c);
    print_area(s);
}
```
上記の例では、 Circle と Square という異なる型を print_area関数の
引数として実行している。

トレイト境界 = ジェネリックの引数にできるtypeか否か

## ジェネリック構造体のトレイト境界
ジェネリック構造体でも同様に trait による型制限ができる。

テキストでは、rectangle が正方形であるかを確認する is_square() メソッドを実装している。


```rust=
struct Rectangle<T> {
    x: T,
    y: T,
    width: T,
    height: T,
}

impl<T: PartialEq> Rectangle<T> {
    fn is_square(&self) -> bool {
        self.width == self.height
    }
}
```

`core::cmp::PartialEq` : == 演算子で比較できることを保証するTrait。このTraitを実装していないtypeを == で比較するとエラー。
基本的なPrimitive型は実装していると思われるが、ジェネリックTを==比較するときは識別ラベルとしてつける必要あり。

## Trait 実装ルール
トレイトはあらゆる型に実装できる。
Primitive型に対しても例外ではない
例. i32 に HasArea トレイトを実装(impl)
可能だけれども、適切ではない

トレイト実装には、手に負えなくなることを防止する2つのルールが有る
1. 自分のスコープ内で定義されていないトレイトは適用されない
2. 自分が実装する impl の対象の型は自分の手によって定義されなければならない

### 1. のルールについて
例えば、File 構造体には std によってWriteトレイトが提供されている。
しかしデフォルトではWriteで定義されるメソッド群を持っていない。

1のルールにより、自分の定義したTraitではないWriteは適用されていない。
File(struct) <- ~~Write(trait)~~ <- .write()(impl)

Traitに対して実装されたimplすなわちメソッドを使うには、
Trait を useする必要がある。

**use** : あるstructに対するTraitを自分のスコープに適用するキーワード
(他にも意味はありそうだが)

```rust=
use std::io::Write;

let mut f = std::fs::File::open("text.txt").expect("can't open");
let result = f.write(b"this is binary");
```

useの文がないと、Writeトレイトが適用されていないので、トレイトに実装された
.write()メソッドは使えない

### .2  のルールについて
i32に対して、 自分で定義したHasArea トレイトは実装できる。
しかし、Rustによってi32に定義されているToStringトレイトを上書きして定義することはできない。

## 複数トレイト境界
\<T> の横に、 `+` でつなげて複数定義できる。
, カンマとかではないので注意

```rust=
use std::fmt::Debug;

fn foo<T: Clone + Debug>(x: T) {
    x.clone();
    println!("{:?}", x);
}
```
この関数のジェネリック引数とする型は、Clone と Debug 両方を実装していなければならない。

## Where節
複数のトレイト境界を記述していくと、関数定義が長くなって邪魔
よって、 **where** キーワードを使って、トレイト境界の記述部分を
後ろの方に分けることができる。

where節の効果
- ジェネリックの境界記述を分ける = 見やすい
- 改行できる = 関数定義の1行を短くする
- 型ごとに異なる処理を実装 = ジェネリックトレイトとのあわせ技

```rust=
fn bar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug {
    // code
}

// 改行できる
fn bar<T, K>(x: T, y: K)
    where T: Clone,
          K: Clone + Debug {
    // code
}

```

## ジェネリックトレイト
struct や impl と同様に、traitにもジェネリックパラメータを付与できる。
where節によって、implで実装する関数の型パラメータごとに異なる処理を実装することも可能


##  デフォルトメソッド
trait には最低でも関数の型を定義すればいい
しかし、実際の処理を実装することもできる。

デフォルトメソッドはimplに実装を書かなくても良い
その場合はデフォルトの処理が実行される。
```rust=
trait Foo {
    fn is_valid(&self) -> bool;

    fn is_invalid(&self) -> bool { !self.is_valid() }
}
```
.is_invalid()メソッドは is_valid() メソッドの反対のbool値を返せば良いので
上記のようにかける。

## 継承
tarit を定義するとき、他のtraitを継承できる
`tarit Trait名 : 継承Trait名 {}`
サブトレイトを適用すると、親トレイトも実装しないとエラー

## #[derive(trait)]
derive = 派生する

標準ライブラリで提供されている、よく使うTraitは core:: で提供される
Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd
- Clone : 自身のコピーを作って返す .clone() メソッド
- Copy  : 代入演算子 = で、自身の値コピーを渡すようになる。move semantics を上書きするトレイト
- Debug   : println! マクロの {:?} のデバックフォーマットで表示する文字列を返すfmt()
- Default : その型のデフォルト値を返すdefault()メソッド
- PartialEq : 実装された型同士を == で比較する eq() , != で比較する ne() メソッド
- Hash : [] でハッシュアクセスできるようになる
- Ord  : [] でオーダードアクセスできるようになる


などなど、よく使うトレイトを自動的に実装してくれる。

その仕組みが、 **#[derive()]** アトリビュート
```rust=
#[derive(Copy, Clone, Debug)]
struct Person {
    name: String,
    age : i32,
}
```
Personオブジェクトに、
- .clone() メソッド
- 値コピー機能
- {:?}フォーマットでの出力文

が自動で実装された


### アトリビュートとは？
宣言を修飾する属性
2種類ある
```rust=
#[attr]
#![attr]
```
! はアトリビュートが適用されるものを変更する
- ! がつかない方: 次にあるアイテムに適用される
- ! がつく方    : #![attr]を囲んでいるアイテムに適用される

**例. #[test] アトリビュート**
つけた関数がテスト関数になる
テストのときだけ実行される。
```rust=
#[test]
fn check1(){
    assert_eq!(2, 1+1);
}

// 上のテスト関数と等価
fn check2(){
    #![test]
    assert_eq!(2, 1+1);
}
```

アトリビュートはRustが言語機能として提供しているもので
ユーザーが独自のアトリビュートを作成することはサポートされていない

### アトリビュートの引数
()で引数を追加できるものもある。
**例. #[cfg()] アトリビュート**
```rust=
#[cfg(target_os = "macos")]
mod macos_only {}
```