2013-02-13 2 views
13

Scala 2.10には、クラスを拡張して指定する値クラスが導入されていますAnyVal。値クラスには多くの制限がありますが、大きな利点の1つは、新しいクラスを作成することなくペナルティなしで拡張メソッドを使用できることです。値クラスを配列に入れるためには、単純に古いクラスと、そのクラスを最初のパラメータとする一連のメソッドです。したがって、 オーバーヘッドなしで価値クラスをどのように充実させますか?

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

は(JVMは、メソッド呼び出しをインライン化したら)自分で i + j*jを書くよりも何より高価になることはできません何かにアンラップします。

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

  • 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 { ... } 
    

    アプローチです。

    答えて

    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プライベート;これが行われた場合は、このトリックを使用することはできません。

    +0

    これは、保存された冗長性 '暗黙のクラス(implicit class) 'が提供するものと直接衝突するため、SIP-15の監視のようです。値クラスが基になる型として値クラスを持つことができない理由についての詳細情報へのリンクはありますか? (コンパイラの制限、実装の複雑さなど) –

    +0

    @AlexDiCarlo - 論理的には必要のない値クラスには多くの制限がありますので、実装を簡略化するために行われたと思います。 –

    関連する問題