15

注:私は自分で答えるためにこの質問を提起していますが、他の答えも歓迎します。

次の簡単な方法を考えてみましょう。

def add[T](x: T, y: T)(implicit num: Numeric[T]) = num.plus(x,y)

次のようにバインドされたコンテキストを使用してこれを書き直すことができます

def add[T: Numeric](x: T, y: T) = ??.plus(x,y) 

しかし、メソッドNumeric[T]を呼び出すことができるように、タイプのインスタンスを取得するにはどうすればよいですか?plus

4

3 に答える 3

24

暗黙的にメソッドを使用する

最も一般的で一般的なアプローチは、Predefで定義されている暗黙的なメソッドを使用することです。

def add[T: Numeric](x: T, y: T) = implicitly[Numeric[T]].plus(x,y)

明らかに、これはやや冗長であり、型クラスの名前を繰り返す必要があります。

証拠パラメータを参照するしないでください!

もう1つの方法は、コンパイラーによって自動的に生成された暗黙の証拠パラメーターの名前を使用することです。

def add[T: Numeric](x: T, y: T) = evidence$1.plus(x,y)

この手法が合法であるのは驚くべきことであり、証拠パラメータの名前が変更される可能性があるため、実際には信頼すべきではありません。

より高い種類のコンテキストメソッドの紹介context

代わりに、implicitlyメソッドの強化バージョンを使用できます。暗黙的にメソッドが次のように定義されていることに注意してください

def implicitly[T](implicit e: T): T = e

このメソッドは、コンパイラーに依存して、周囲のスコープからメソッド呼び出しに正しい型の暗黙のオブジェクトを挿入し、それを返します。もう少しうまくやることができます:

def context[C[_], T](implicit e: C[T]) = e

addこれにより、メソッドを次のように定義できます。

def add[T: Numeric](x: T, y: T) = context.plus(x,y)

contextメソッドタイプパラメータNumericとはTスコープから推測されます!残念ながら、このcontext方法が機能しない状況があります。たとえば、型パラメーターに複数のコンテキスト境界がある場合、または異なるコンテキスト境界を持つ複数のパラメーターがある場合。後者の問題は、もう少し複雑なバージョンで解決できます。

class Context[T] { def apply[C[_]]()(implicit e: C[T]) = e }
def context[T] = new Context[T]

このバージョンでは、毎回タイプパラメータを指定する必要がありますが、複数のタイプパラメータを処理します。

def add[T: Numeric](x: T, y: T) = context[T]().plus(x,y)
于 2010-12-07T03:33:57.020 に答える
7

少なくともScala2.9以降は、次のことができます。

import Numeric.Implicits._
def add[T: Numeric](x: T, y: T) = x + y

add(2.8, 0.1) // res1: Double = 2.9
add(1, 2) // res2: Int = 3
于 2011-05-21T15:34:40.780 に答える
4

この回答は、より読みやすく、自己文書化されたクライアントコードをもたらす別のアプローチについて説明しています。

動機

前に説明したcontextメソッドは、追加の作業なしで、任意の型クラスで機能する非常に一般的なソリューションです。ただし、次の2つの理由で望ましくない場合があります。

  • contexttypeパラメーターに複数のコンテキスト境界がある場合、コンパイラーにはどのコンテキスト境界が意図されているかを判別する方法がないため、このメソッドは使用できません。

  • ジェネリックcontextメソッドへの参照は、クライアントコードの可読性を損ないます。

タイプクラス固有のメソッド

目的の型クラスに関連付けられているメソッドを使用すると、クライアントコードがはるかに読みやすくなります。これは、マニフェスト型クラスの標準ライブラリで使用されるアプローチです。

// definition in Predef
def manifest[T](implicit m: Manifest[T]) = m

// example usage
def getErasure[T: Manifest](x: T) = manifest[T].erasure

このアプローチの一般化

型クラス固有のメソッドを使用する主な欠点は、すべての型クラスに対して追加のメソッドを定義する必要があることです。次の定義を使用して、このプロセスを容易にすることができます。

class Implicitly[TC[_]] { def apply[T]()(implicit e: TC[T]) = e }
object Implicitly { def apply[TC[_]] = new Implicitly[TC] }

次に、任意の型クラスに対して、新しい型クラス固有の暗黙的なスタイルのメソッドを定義できます。

def numeric = Implicitly[Numeric]
// or
val numeric = Implicitly[Numeric]

最後に、クライアントコードは次のように暗黙的に使用できます。

def add[T: Numeric](x: T, y: T) = numeric[T].plus(x, y)
于 2011-07-13T22:32:45.653 に答える