繁体   English   中英

Scala类型参数的隐式转换

[英]Scala implicit conversion of type parameters

我正在尝试创建一个可以将一个单位的距离转换为另一个单位的库。 理想情况下,我能够以一个单位指定距离,当传递给需要不同单位的方法时,让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()

在没有显式说明type参数的情况下使用它似乎使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     

遵循编译器的建议,结果foo返回10.0inch,10.0inch而不是预期的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                        

我是在做错什么,还是编译器不允许使用这种隐式转换?

你只需要

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))

或类似的东西。 (正如您现在所定义的,顺便说一下,转换是向后的。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM