Scalaでは、少なくとも2つの方法を使用して、既存の型または新しい型を改良できます。を使用して何かを数量化できることを表現したいとしInt
ます。次の特性を定義できます。
暗黙的な変換
trait Quantifiable{ def quantify: Int }
そして、暗黙の変換を使用して、たとえば文字列やリストを定量化できます。
implicit def string2quant(s: String) = new Quantifiable{
def quantify = s.size
}
implicit def list2quantifiable[A](l: List[A]) = new Quantifiable{
val quantify = l.size
}
これらをインポートした後quantify
、文字列とリストのメソッドを呼び出すことができます。定量化可能なリストはその長さを格納するため、後続のへの呼び出しでのリストの高価な走査を回避することに注意してくださいquantify
。
型クラス
別の方法はQuantified[A]
、あるタイプA
は数量化できることを示す「目撃者」を定義することです。
trait Quantified[A] { def quantify(a: A): Int }
私たちは、このタイプのクラスのインスタンスを提供String
し、List
どこかに。
implicit val stringQuantifiable = new Quantified[String] {
def quantify(s: String) = s.size
}
次に、引数を定量化する必要があるメソッドを作成する場合は、次のように記述します。
def sumQuantities[A](as: List[A])(implicit ev: Quantified[A]) =
as.map(ev.quantify).sum
または、コンテキストにバインドされた構文を使用します。
def sumQuantities[A: Quantified](as: List[A]) =
as.map(implicitly[Quantified[A]].quantify).sum
しかし、どの方法を使用するのですか?
今問題が来ます。これらの2つの概念をどのように判断できますか?
これまで気付いたこと。
型クラス
- 型クラスにより、コンテキストに適した構文が可能になります
- 型クラスでは、使用するたびに新しいラッパーオブジェクトを作成しません
- 型クラスに複数の型パラメーターがある場合、コンテキストにバインドされた構文は機能しなくなります。整数だけでなく、いくつかの一般的なタイプの値で物事を数量化したいと想像してください
T
。型クラスを作成したいQuantified[A,T]
暗黙の変換
- 新しいオブジェクトを作成するので、そこに値をキャッシュしたり、より適切な表現を計算したりできます。しかし、これは何度か発生する可能性があり、明示的な変換はおそらく一度だけ呼び出されるため、これを回避する必要がありますか?
答えに期待すること
両方の概念の違いが重要である1つ(または複数)のユースケースを提示し、なぜ私が一方を他方よりも好むのかを説明します。また、2つの概念の本質とそれらの相互関係を説明することは、例がなくてもよいでしょう。
size
では、リストのを値に格納し、それが数量化のための後続の呼び出しでのリストの高額な走査を回避しますがquantify
、list2quantifiable
gets へのすべての呼び出しでトリガーされますつまり、Quantifiable
を再インスタンス化し、quantify
プロパティを再計算します。私が言っているのは、暗黙の変換で結果をキャッシュする方法は実際にはないということです。