2016-09-01 11 views
5

私たちが知っているように、異なる数の異なる2つの数値を加算(減算/乗算など)することができ、その結果はその順序にかかわらず2種類のうちより広いものになります。型パラメータと数値の拡大

33F + 9L // Float + Long == Float 
33L + 9F // Long + Float == Float 

7つのNumericクラス(ByteShortCharIntLongFloatDouble)の各々は、7つの異なる+()方法有するので、これは、(及び-()を等、*())毎Numericタイプのものです渡されたパラメータとして受け取ることができます。 [あり余分+()方法はStringパラメータを処理するためだが、それは、ここで私たちを気にする必要はありません。]

は今すぐ次の点を考慮してください

implicit class PlusOrMinus[T: Numeric](a: T) { 
    import Numeric.Implicits._ 
    def +-(b: T) = if (util.Random.nextBoolean) a+b else a-b 
} 

これは、2つのオペランドが同じタイプであれば動作しますが、それ第1オペランドの型が第2型の型よりも広い場合にも有効です。私はここで何が起こっていると考えている

11F +- 2L // result: Float = 9.0 or 13.0 

は、コンパイラは、それが+-()メソッドに渡されたとして、第二オペランド(bパラメータ)にnumeric wideningを達成するためにweak conformanceを使用していることです。

ただし、第1オペランドは第2オペランドと一致するように拡大されません。それはコンパイルされません。

11L +- 2F // Error: type mismatch; found: Float(2.0) required: Long 

この制限はありますか?

Numericは、型パラメータで表現し、それだけの独自のタイプを加算/減算することができますので、私は b引数( def +-[U: Numeric](b: U) = ...)のための異なるタイプのパラメータを使用することはできません

は、7種類の方法で7つの異なるクラス(PlusOrMinusShort/Int/Long/など)を作成するための唯一のソリューションです(def +-(b:Short)def +-(b:Int)def +-(b:Long)、など)?ここで

答えて

4

が道である:

implicit class PlusOrMinus[T: Numeric](a: T) { 
    import Numeric.Implicits._ 
    def +-(b: T) = plusOrMinus(a,b) 
    def +-[U: Numeric](b: U)(implicit ev: T => U) = plusOrMinus[U](a,b) 

    private def plusOrMinus[W: Numeric](a: W, b: W): W = 
    if (util.Random.nextBoolean) a+b else a-b 
} 

すると、これで、私は次のような相互作用を得る:

scala> 11F +- 2L 
res0: Float = 9.0 

scala> 11L +- 2F 
res1: Float = 9.0 

アイデアは、私はちょうど機能plusOrMinusを持っていることができればということで、いずれの議論についても同じ広がりが起こる可能性があるため、この全体的な問題は軽微です。そのような関数を定義した後で、それを暗黙のクラスに埋め込み、それを中置形式で使用する方法になります。

ここでは、2つ目の引数を増やす必要があるか、暗黙的なクラスでラップされた引数を広げる必要があるケースが2つしかありません。これらのケースの1つ目は最初の+-メソッドでカバーされています(上記の理由により)。しかし、2番目のケースでは、可能な変換があると明示して、変換の汎用タイプをplusOrMinusに渡す必要があります。

関連する問題