13

Scala 2.10 では値クラスが導入されており、これはクラスを extends にすることで指定できますAnyVal。値クラスには多くの制限がありますが、それらの大きな利点の 1 つは、新しいクラスを作成するペナルティなしで拡張メソッドを使用できることです。値クラスを配列に入れるなどのボックス化が必要でない限り、それは単純に古いクラスに加えたものです。クラスを最初のパラメーターとして受け取る一連のメソッド。したがって、

implicit class Foo(val i: Int) extends AnyVal {
  def +*(j: Int) = i + j*j
}

i + j*j(JVM がメソッド呼び出しをインライン化すると) 自分で作成するよりもコストがかからないものにアンラップします。

残念ながら、値クラスを記述するSIP-15の制限の 1 つは、

  1. C の基になる型は、値クラスではない場合があります。

たとえば、ボクシングのオーバーヘッドなしでタイプセーフなユニットを提供する方法として、手に入れることができる値クラスがある場合 (本当に必要な場合を除く):

class Meter(val meters: Double) extends AnyVal {
  def centimeters = meters*100.0                // No longer type-safe
  def +(m: Meter) = new Meter(meters+m.meters)  // Only works with Meter!
}

それでは、Meterオブジェクト作成のオーバーヘッドなしでエンリッチする方法はありますか? SIP-15 の制限により、明らかな

implicit class RichMeter(m: Meter) extends AnyVal { ... }

アプローチ。

4

1 に答える 1

14

値クラスを拡張するには、基になる型を再キャプチャする必要があります。値クラスは、ラップされたタイプにアクセスできるようにする必要があるため(上val i​​記だけでなくi)、いつでもこれを行うことができます。便利なショートカットを使用することはできませんがimplicit class、暗黙の変換をロングハンドで追加することはできます。したがって、-メソッドを追加するMeter場合は、次のようなことを行う必要があります。

class RichMeter(val meters: Double) extends AnyVal {
  def -(m: Meter) = new Meter(meters - m.meters)
}
implicit def EnrichMeters(m: Meter) = new RichMeter(m.meters)

また、元の値クラスで任意のパラメーターを(自由に)再ラップできることにも注意してください。したがって、依存する機能がある場合(たとえば、ラップするLongが複雑なビットミキシングを実行する場合)、基になるクラスを必要な場所に拡張しようとしている値クラス。

(あなたがいない限り、警告が表示されることにも注意してくださいimport language.implicitConversions。)

補遺:Scala 2.11以降では、valプライベートにすることができます。これが行われた場合、このトリックを使用することはできません。

于 2013-02-13T20:00:15.913 に答える