Rust備忘録〜Trait(トレイト境界), impl〜
Rust備忘録〜Trait(トレイト境界), impl〜
環境
- macOS
- rustc 1.33.0
サンプルコード(
https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/traits.html
)
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); }
Trait
もしHasArea Traitがなければ"T型"にareaメソッドなんてもんねーぞ的なエラーが出る。なぜならT型はどのような型にもなれるため、受け取った引数がどのような型にもなれるT型としか分からないコンパイラはコンパイルすることができないからである。
ここでtrait機能を使う。使うとコンパイラにT型の引数を取ったメソッドを使ったらこのtraitの中にあるメソッドだけ使ってくれやと伝えることができる。
つまり、TraitというのはT型を制限するシステム(トレイト境界)である。
impl
型にメソッドを実装する。
例えば、Square型とCircle型で同名だけど内容は違うメソッド(areaメソッド)を使いたい場合、implがなければif文で分岐する感じになるが、implを使えば引数がCircle型ならimpl Circleのareaメソッドが、引数がSquare型ならimpl Squareのareaメソッドが使える。
impl Trait for stract
型にそのTraitのメソッドを実装させることができる。
例えば
#[derive(Clone)] pub struct MatrixOne<T> { vec: Vec<T>, dim: usize, } //配列へアクセスするためにIndexトレイトをMatrixOneに実装 impl<T, I: SliceIndex<[T]>> Index<I> for MatrixOne<T> { type Output = I::Output; #[inline] fn index(&self, index: I) -> &Self::Output { Index::index(&self.vec, index) } }
MatrixOne内のVec型のメンバ変数に[x]でアクセスしたい際はIndexトレイトをMatrixOneに実装する。
型にメソッドを実装したい時はimpl Trait for structとするだけで良いのである。強い(あまり理解していない。)
ちなみに
#[derive(Clone)] pub struct MatrixOne<T> { vec: Vec<T>, dim: usize, }
#[derive(Clone)]というのはアトリビュートと呼ばれるもので、こいつもまたコンパイラに機能を伝えてくれるやつである。
#[derive(Trait名)]は、型の上に追記させることでその型にそのTraitのメソッドを実装してくれる。impl何とかかんとかといちいち書かなくて良いのである。
アトリビュート一覧は下のURL
https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/reference.html#attributes
補足
"型にメソッドを実装する"
型にメソッドを実装する=その型だけでしか使えないメソッドを作成する
という意味である。
メリットとしては
- バグが少なくなる(型でメソッドの挙動を制限できるから)
- implで述べた通り、型で条件分岐ができるようになる