スポンサーリンク

Rustやってみる(9)関数でGenericsを使ってみる

1.自分で実装する場合

まず以下のように定義する。

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
  }
}

例1

失敗例1

まず、以下のようにただ<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); }

修正1

「型Tを取る」ではなく、「get_pow2()を持つ型Tを取る」と記述しなければいけない。

// T は TraitMyPow を実装していなければならない
fn call< T : TraitMyPow >(value:T){
  println!("call {}",value.get_pow2());
}

例2

トレイトは + で複数指定できる。

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していない

}

2.operatorを使用可能にする

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);

}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: