0

ある単位から別の単位に距離を変換できるライブラリを作成しようとしています。理想的には、距離を 1 つの単位で指定でき、別の単位を必要とするメソッドに渡されたときに、scala コンパイラーに自動的に変換させることができます。これは私がこれまでに持っているものです:

abstract class BaseUnit(scale: Option[Double] = None) {
  def unit: String

  def scalingFactor: Double = scale match {
    case Some(factor) => factor
    case None => 1.0
  }
}

object Cm {
  implicit def inch2cm(inch: Inch):Cm = new Cm(Some(0.393 * inch.scalingFactor))
}

class Cm(scale: Option[Double] = None) extends BaseUnit(scale) {
  def unit: String = "cm"
}

object Inch {
  implicit def cm2inch(cm: Cm):Inch = new Inch(Some(2.54 * cm.scalingFactor))
}

class Inch(scale: Option[Double] = None) extends BaseUnit(scale) {
  def unit: String = "inch"
}

class Distance[A <: BaseUnit](val scalar: Double, val unit: A) {
  override def toString: String = (scalar*unit.scalingFactor)+unit.unit
}


def foo(x: Distance[Cm], y: Distance[Cm]): String = x.toString()+","+y.toString()

型パラメーターを明示的に指定せずに使用すると、Scala はNothing型を使用するようになります。

val a = new Distance(10, new Inch)                                         

println(foo(a, a))                                                               

> scala test.scala

 found   : this.Distance[Nothing]                                   
 required: this.Distance[this.Cm]                                   
Note: Nothing <: this.Cm, but class Distance is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)                   
println(foo(a, a))                                                  
            ^                                                       
one error found     

10.0inch,10.0inchコンパイラの提案に従うと、予想されるのではなくfoo が返され3.93cm,3.93cmます。

型を明示的に指定すると、コンパイラは違いを認識しますが、暗黙のうちに型を別の型に変換することはありません。

val a = new Distance[Inch](10, new Inch)

println(foo(a, a))                      

// found   : this.Distance[this.Inch]    
// required: this.Distance[this.Cm]      
//  println(foo(a, a))                     
//              ^                          
//  one error found                        

私は何か間違ったことをしていますか、それともコンパイラはこの暗黙的な変換の使用を許可していませんか?

4

1 に答える 1

1

あなたはただする必要があります

class Distance[A <: BaseUnit](val scalar: Double, val unit: A) { ... }

Aコンパイラがあまり具体的にしない理由があるように。Nothingそれ以外の場合は、あなたがしていることとは関係がないので自由に選択できます。

また、単位間の変換方法は知っていますが、距離間の変換方法は教えていません。あなたはできる:

implicit def convertDist[A <: BaseUnit, B <: BaseUnit](da: Distance[A])(implicit a2b: (A => B)): Distance[B] = new Distance[B](da.scalar, a2b(da.unit))

またはそのようなもの。(ちなみに、今定義したように、変換は逆です。)

于 2013-03-30T15:31:14.420 に答える