2017-03-14 8 views
3

Quantityという定義済みの値クラスに数値演算を追加しようとしています。私は次のように、これは使用していたコード...値のクラスを持つ暗黙的な変換とmkNumericOpsのスキャレート

import scala.language.implicitConversions 

case class Quantity(value: Double) extends AnyVal 

object Quantity { 
    implicit def mkNumericOps(lhs: Quantity): QuantityIsNumeric.Ops = QuantityIsNumeric.mkNumericOps(lhs) 
} 

object QuantityIsNumeric extends Numeric[Quantity] { 

    def plus(x: Quantity, y: Quantity): Quantity = Quantity(x.value + y.value) 

    def minus(x: Quantity, y: Quantity): Quantity = Quantity(x.value - y.value) 

    def times(x: Quantity, y: Quantity): Quantity = Quantity(x.value * y.value) 

    def negate(x: Quantity): Quantity = Quantity(-x.value) 

    def fromInt(x: Int): Quantity = Quantity(x.toDouble) 

    def toInt(x: Quantity): Int = x.value.toInt 

    def toLong(x: Quantity): Long = x.value.toLong 

    def toFloat(x: Quantity): Float = x.value.toFloat 

    def toDouble(x: Quantity): Double = x.value 

    def compare(x: Quantity, y: Quantity): Int = x.value compare y.value 
} 

次のように私はこのコードを使用して...

class SortedAskOrders[T <: Tradable] private(orders: immutable.TreeSet[LimitAskOrder[T]], val numberUnits: Quantity) { 

    def + (order: LimitAskOrder[T]): SortedAskOrders[T] = { 
    new SortedAskOrders(orders + order, numberUnits + order.quantity) 
    } 

    def - (order: LimitAskOrder[T]): SortedAskOrders[T] = { 
    new SortedAskOrders(orders - order, numberUnits - order.quantity) 
    } 

    def head: LimitAskOrder[T] = orders.head 
    def tail: SortedAskOrders[T] = new SortedAskOrders(orders.tail, numberUnits - head.quantity) 
} 

...私がしようとすると、このコードをコンパイルするとき、私は次のエラーを取得します..

Error:(29, 63) type mismatch; 
found : org.economicsl.auctions.Quantity 
required: String 
     new SortedAskOrders(orders + order, numberUnits + order.quantity) 

明示的に暗黙の型変換使用+方法の次の実装(私はすでにスコープ内にあるべきと思った!)動作します。

def + (order: LimitAskOrder[T]): SortedAskOrders[T] = { 
    new SortedAskOrders(orders + order, Quantity.mkNumericOps(numberUnits) + order.quantity) 
} 

コンパイラは、数値+オペレータのための暗黙的な変換を見つけることができるとは思われません。思考?

暗黙的な変換とNumeric特性を使用して、値クラスの数値演算を作成するのはかなり標準的だと思っていました。私は間違って何をしていますか?

+0

あなたのファイルの上に 'import Quantity._'があるようです。 –

+0

@YuriyGatilinしかし、インポートステートメントがなくても、コンパイラは減算演算子の暗黙の変換を見つけることができます。私は何か他のことが起こっていると思います... – davidrpugh

+0

これは暗黙的なスコープ内/外での問題ではありません。他の操作( ' - '、 '*'など)は、苦情なしにコンパイルするようです。いいえ、コンパイラが暗黙的に探していないことはかなり明白です。なぜなら、 '+'は文字列の連結演算であり、すべてが文字列表現をしているので、暗黙の必要はありません。私は少なくとも1つの回避策を知っていますが、このことをより深く理解している誰かが、ストリングコンカットをオフにするクリーンでシンプルな手段で飛び立つことを望んでいました。 – jwvh

答えて

3

問題は、豊富な操作をサポートする変換を提供している間は、優先度がscala.Predef.any2stringaddより低いことです。あなたはここでは適用できないの実装でany2stringadd名前をシャドウイングすることによって、これを確認することができます。

scala> implicit def any2stringadd(i: Int): Int = i 
any2stringadd: (i: Int)Int 

scala> def add(a: Quantity, b: Quantity): Quantity = a + b 
add: (a: Quantity, b: Quantity)Quantity 

輸入暗黙は(常にコンパニオンオブジェクトで定義された暗黙に優先します、とPredefは、暗黙的にすべてのソースファイルにインポートされますしない限り、私は非常にお勧めします-Yno-predefを有効にした、少なくともライブラリコード)。

Predefを無効にしない限り、この唯一の方法はコンバージョンをインポートすることです(ユーザーがPredefをオフにできる場合でも、ユーザーはできない可能性があります)。

注意点として、あなたは型クラスとしてNumericを使用して、このコードは、多くの慣用的なことができます:

case class Quantity(value: Double) extends AnyVal 

object Quantity { 
    implicit val quantityNumeric: Numeric[Quantity] = new Numeric[Quantity] { 
    def plus(x: Quantity, y: Quantity): Quantity = Quantity(x.value + y.value) 
    def minus(x: Quantity, y: Quantity): Quantity = Quantity(x.value - y.value) 
    def times(x: Quantity, y: Quantity): Quantity = Quantity(x.value * y.value) 
    def negate(x: Quantity): Quantity = Quantity(-x.value) 
    def fromInt(x: Int): Quantity = Quantity(x.toDouble) 
    def toInt(x: Quantity): Int = x.value.toInt 
    def toLong(x: Quantity): Long = x.value.toLong 
    def toFloat(x: Quantity): Float = x.value.toFloat 
    def toDouble(x: Quantity): Double = x.value 
    def compare(x: Quantity, y: Quantity): Int = x.value compare y.value 
    } 
} 

代わりNumericをインスタンス化したオブジェクトを有し、かつ明示的にそのOPSインスタンスを使用しての、すなわち、あなたコンパニオンオブジェクトにNumericタイプクラスの暗黙のインスタンスを提供するだけです。今、あなたはOPS構文法の任意の使用するためにインポートが必要です。

scala> import Numeric.Implicits._ 
import Numeric.Implicits._ 

scala> def add(a: Quantity, b: Quantity): Quantity = a + b 
add: (a: Quantity, b: Quantity)Quantity 

をしかし、これは他のScalaのユーザーが知っている可能性が高いことを標準のインポートではなく、あなたが説明する必要がカスタムの事です別々に。

+0

私はライブラリコードを書いています。そして、いくつかの掘り出しの後に、 'Yno-predef'コンパイラフラグを使うことが行く方法だと思います。これは、自分のjarファイルをそれぞれのプロジェクトに追加するJava/Scalaのダウンストリームユーザーにどのように影響しますか?私はcatがこのコンパイラフラグを使用していないことに気付きました... – davidrpugh

+0

@davidrpugh実行時や公開された成果物には何の影響もありません(その名前が示唆していますが)。暗黙的な 'importコンパイラがあなたのソースファイルを処理しているときに通常取得する「Predef._」です。 –

関連する問題