21

比較演算子を実行したいパラメーター化された型を持つクラスがあります。これを達成するには Ordered トレイトを使用する必要があると思いますが、コンパイラはそれを使用することを好みません。だから私は次のクラスを持っているとしましょう:

class Test[T <: Ordered[T]] {

  def someOp(t: T) if(t < 3) ...
  ...
}

ただし、このクラスを次のように使用しようとすると:

val test = new Test[Int]()

コンパイラは次のように文句を言います。

型引数 [Test[Int]] は、クラス Test の型パラメーター境界 [T <: Ordered[T]] に準拠していません

誰かが私がここで間違っていることを説明できますか?

4

2 に答える 2

14

Ordering[T]型クラスを暗黙のパラメーターとして使用できます。一般的な max 関数を書きたい場合は、次のようになります。

def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = { 
  if(ordering.gt(a,b)) a else b 
}

Int、Float などのプリミティブ データ型の場合、暗黙の Ordering[T] がスコープ内にあるため、期待どおりに使用できます。

max(1,2) // gives 2

Ordered[T] を実装するすべての型には、Ordering[T] を提供するための暗黙的なものもあります。

順序付けを組み合わせるさまざまなメソッドもスコープ内にあります。たとえば、各要素に Ordering[T] がある N タプルがある場合、タプル タイプの Or​​dering が自動的に存在します。

max((1,2), (3,4)) // gives (3,4) because 3 is larger than 1

しかし、暗黙的に提供された順序付けのいずれにも満足できない場合は、独自の順序付けを作成して明示的に渡すか、スコープ内で暗黙的な val として取得することもできます。このような:

val negativeIntOrdering = new Ordering[Int] { 
  def compare(a:Int,b:Int) = b - a 
}

max(1,2)(negativeIntOrdering) // gives 1

したがって、型クラス ベースのアプローチは、継承ベースのアプローチよりもはるかに柔軟です。これが、 spireのような数学ライブラリが広く使用する理由です。

上記のコードが良くない点の 1 つは、演算子の代わりに lt メソッドを使用する必要があることです。しかし、それにも解決策があります。Ordering には、T の演算子を提供する mkOrderingOps という暗黙のメソッドがあります。次のように、ordering._ をインポートしてスコープ内で取得する必要があります。

def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = { 
  import ordering._; 
  if(a>b) a else b 
}
于 2013-10-15T18:49:18.750 に答える