まず以下のように定義する。
struct IntValue ... TraitMyDisp と TraitMyPow 実装
struct FloatValue ... TraitMyPow のみ実装
// これをimplementしているときは表示できる trait TraitMyDisp{ fn disp(&self); } // これをimplementしているときは値を二乗する trait TraitMyPow{ fn get_pow2(&self)->f32; } ////////////////////////////////////////// //////////////////////////////////////////struct IntValue{ value: i32 } impl TraitMyDisp for IntValue{ fn disp(&self){ println!("{}",self.value); } } impl TraitMyPow for IntValue{ fn get_pow2(&self)->f32{ ( self.value*self.value ) as f32 } }////////////////////////////////////////// //////////////////////////////////////////struct FloatValue{ value:f32 } impl TraitMyPow for FloatValue{ fn get_pow2(&self)->f32{ ( self.value*self.value ) as f32 } }
まず、以下のようにただ<T>を渡してもコンパイルは通らない。
// C++だと T に get_pos2があればビルドが通るが // Rustでは valueに対して何をできるのかを指定しなければならない fn call<T>(value:T){ println!("call {}",value.get_pow2()); // NG T にget_pow2が必要なんて聞いてない }
fn main(){ // TraitMyDisp , TraitMyPow の両方が実装済み let i_val = IntValue{value:2}; // TraitMyPow のみが実装済み let f_val = FloatValue{value:2.0}; call(i_val); }
「型Tを取る」ではなく、「get_pow2()を持つ型Tを取る」と記述しなければいけない。
// T は TraitMyPow を実装していなければならない fn call< T : TraitMyPow >(value:T){ println!("call {}",value.get_pow2()); }
トレイトは + で複数指定できる。
T は+で指定されたすべてのトレイトに対応していなければならない。
たとえその関数の中で使っていなくても、実装だけはしていなければならない。
// <T:トレイト + トレイト> のように+で複数指定できる fn call_both<T:TraitMyPow + TraitMyDisp>(value:&T){ // TraitMyDisp::dispは使っていないが、トレイト境界を指定しているので // Tがdispに対応していないならコンパイルできない(たとえ使っていなくても) println!("call {}",value.get_pow2()); } fn main(){ // TraitMyDisp , TraitMyPow の両方が実装済み let i_val = IntValue{value:2}; // TraitMyPow のみが実装済み let f_val = FloatValue{value:2.0}; call_both(&i_val); // OK // call_both(&f_val); // NG FloatValueのためのTraitMyDispはimplしていない }
Tに渡される型が + 演算できるかどうかはわからない。
したがって、例え自分がプリミティブな数値型しか与えるつもりがなくても、コンパイラはそんなことは知らないので「TはAddが可能である」ことを教えなければいけない。
// Addモジュールを使う use std::ops::Add; ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
// add関数の定義 // Tの必須の振る舞いとしてAddを指定。これで operator + が使える fn add< T : Add<Output=T> >( v1:T , v2:T ) -> T { v1 + v2 }
fn main(){ let val:i32 = add( 3,4); }