Rustのstruct、traitの使い方


Rustのstruct/traitが大分手に馴染んできた気がするのでメモ
ここではx,yを持つPoint型と言うのを例に基本的な使い方を紹介する。

## Structの定義

まず構造体を定義する。

```rust
pub struct Point<T> {
    pub x: T,
    pub y: T
}
```

一番基本的な形は以下だが、

```rust
struct Point<T> {
    x: T,
    y: T
}
```

`pub`というキーワードでメンバをpublicにするのと、
structを外部から選べるようにしてる。


## コンストラクタ・スタティックメソッド

コンストラクタはC++のように専用のものがあるわけではなく、
スタティックメソッドとして実現する。

```rust
impl<T> Point<T> {
    pub fn new(p:(T,T)) -> Point<T> {
        Point{x:p.0,y:p.1}
    }
}
```

これはそんなに難しくないと思う
`T`型のタプルを引数にとってそれをx,yに割り当てて（暗黙の）returnしてる。

### 使い方

こういう風に使う

```rust
fn foo(){
	let p = Point::new((0u32,0));
	println!("{}",p.x);
}
```
ここでタプルの2つ目の要素の型は型推論によって自動的にu32と推定してくれる。


またはこう

```rust
fn foo(){
	Point::<u32>::new((0,0));
	println!("{}",p.x);
}
```

## インスタンスメソッド

インスタンスメソッドは以下のようにselfで自身を参照する

```rust
impl<T:Mul+Div+Copy> Point<T> where <T as Mul>::Output:Add {

    pub fn div(&self, d:T) -> Point<<T as Div>::Output> {
        Point{x:self.x/d,y:self.y/d}
    }

    pub fn dot(&self, r: Point<T>) -> <<T as Mul>::Output as Add>::Output {
        self.x * r.x + self.y * r.y
    }

}
```

### 型制約

型制約の部分がいきなり複雑になった印象があるかもしれないが、
すこしずつ見ていけばそんなに難しくない。


`impl<T:Mul+Div+Copy>`この部分で`Point`型の引数としてとる`T`が
`Mul`というtraitと`Div`というtraitと`Copy`というtraitを持つ事を要求してる。

そしてさらに複雑な型制約を`where`句以降に書いている。
型制約の部分は以下の様に`where`句の後にまとめることもできる。

```rust
impl<T> Point<T> where T:Mul+Div+Copy,<T as Mul>::Output:Add {
```

メソッドの部分を見ていく。


```rust
    pub fn div(self, d:T) -> Point<<T as Div>::Output> {
        Point{x:self.x/d,y:self.y/d}
    }
```

これは`d:T`を受け取って`x`,`y`をそれぞれ割るメソッドとして受け取る。

返り値の型は `Point<T>` と書きたくなるが、
`T:Div`をdivした値は`T`とは限らない（大概は`T`だが）ので
`Div`のtraitでは`T::Output`として別に型を持っていてそちらを
型引数として持つ`Point`となる

また、`/`演算子は`Copy`traitを要求するのでTには`Copy`traitも必要。

演算子による演算の結果として型が変わる様な例は
ベクトルの内積のようなものを思い浮かべるといいだろう
rustはそのようなケースでも柔軟に記述できるようになっている。


#### より複雑なケース


```rust
    pub fn dot(self, r: Point<T>) -> <<T as Mul>::Output as Add>::Output {
        self.x * r.x + self.y * r.y
    }
```

これはまさに内積の計算だが、アウトプットは
`mul`した際の`Output`を`add`した`Output`となってる。
（`Point<<<T as Mul>::Output as Add>::Output>`ではなく
　`<<T as Mul>::Output as Add>::Output`）

この計算をする上で先ほど`where`句で指定した
`<T as Mul>::Output:Add`という型指定が活きてくる。

Rustのこの辺りの型指定の柔軟さはすごくかっこいいと思う。

## 既存のtraitを埋め込む

Point同士の加算を演算子で表現したいとかいう要件がある。
例えば

```rust
fn foo(){
	let p = Point::new((0u32,0));
	let q = Point::new((0u32,0));
	println!("{},{}",(p+q).x,(p+q).y);
}

```


これを実現するには`Add`traitの実装を書く

```rust
impl<T:Add> Add for Point<T> {
    type Output = Point<<T as Add>::Output>;
    fn add(self, r: Point<T>) -> Point<<T as Add>::Output> {
        Point{x:self.x + r.x , y:self.y + r.y}
    }
}
```

殆ど説明は必要ないと思うけど、`pub`修飾子はいらないらしい。

これで、`Add`trait自体の埋め込みは終わるが、
`add`関数は参照ではなく値を要求するので
一度`add`演算子を使った時点でmoveされる事になってしまい実用的ではない。
そのため、`Point<T>`自体に`Copy`traitを実装する必要が有る。
`Copy`traitの実装はわざわざ自分で書く必要はなく
struct定義の前に`#[derive(Copy, Clone)]`をつけるだけでやってくれる。（！）

```rust
#[derive(Copy, Clone)]
pub struct Point<T> {
    pub x: T,
    pub y: T
}
```

### debug print

`println!("{:?}",p)`とかで表示したい気持ちが生まれてくると思うが、
その場合は`std::fmt::Debug`traitを実装しておく。

```rust
impl<T> fmt::Debug for Point<T> where T:fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({:?},{:?})", self.x, self.y)
    }
}
```

※`use std::fmt;`が必要


## まとめ

Rustのstruct/traitの基本的な使い方をまとめた。
ここで書いたことくらいがあれば特にc++ユーザなんかは
rustのstruct/traitを実用的に使っていけるのではないかと思う。