具有数字类型的协变数据结构

时间:2018-03-16 15:47:22

标签: scala generics types

如何创建包含数字数据类型的协变数据结构?

在scala中,我可以创建一个协变数据结构,其中包含类型参数的层次结构:

abstract class Car[+T] {
  def value: T
}
class RaceCar extends Car[RacingWheel] {
  def value: RacingWheel = new RacingWheel
}
class NormalCar extends Car[BoringWheel] {
  def value: BoringWheel = new BoringWheel
}

class Wheel
case class RacingWheel() extends Wheel
case class BoringWheel() extends Wheel

object Car {
  def main(args: Array[String]): Unit = {
    val rCar: Car[Wheel] = new RaceCar
    val nCar: Car[Wheel] = new NormalCar
    val listCars: List[Car[Wheel]] = List(rCar, nCar)
  }
}

但是,当我用数字数据类型替换Wheel时,我遇到了问题,因为数字数据类型没有AnyVal以外的公共类型父类:

abstract class Item[+N] {
  def value: N
}
class IntItem(x : Int) extends Item[Int] {
  override def value: Int = x
}
class DoubleItem(x : Double) extends Item[Double] {
  override def value: Double = x
}

object Item {
  def main(args: Array[String]): Unit = {
    // ERROR Expression of IntItem does not conform to expected type Item[Number]
    val iItem: Item[Number] = new IntItem(10)
    // ERROR Expression of DoubleItem does not conform to expected type Item[Number]
    val dItem: Item[Number] = new DoubleItem(10.9)
    val l: List[Item[Number]] = List(iItem, dItem)

    // ERROR: Expression of IntItem does not conform to expected type Item[Double]
    val iItem2: Item[Double] = new IntItem(10)
    val dItem2: Item[Double] = new DoubleItem(10.9)
    val l2: List[Item[Double]] = List(iItem2, dItem2)
  }
}

在协变数据结构之外,我得到了混合结果:

object NumberMain {
  val a : Int = 5
  val b : Double = 10.0
  val list : List[Number] = List(a, b)
  // works, so Number must be related to Int and Double, right?

  val x : Number = 5
  // ERROR: Expression of type Number doesn't conform to expected type Int
  val y : Int = x
  // does not work, so Number is not related to Int and Double after all...
}

我必须对Item数据结构进行哪些更改?我可以告诉它所有项目都可以看作是数字类型吗?

1 个答案:

答案 0 :(得分:1)

在Scala中,sortFile()Int不与共同的Double类共享层次结构。在这些情况下,Typeclass pattern可以帮助您为没有常见超类型的类型定义额外的功能。

Number

trait MyNumber[A] implicit case object IntMyNumber extends MyNumber[Int] implicit case object DoubleMyNumber extends MyNumber[Double] class Item[N](x: N)(implicit n: MyNumber[N]) { def value: N = x } 类构造函数现在需要使用Item关键字标记的第二组参数。如果在没有这组参数的情况下调用方法,编译器会尝试从变量或导入中找到它(implicit的实例),并且标记为MyNumberWhere does Scala look for implicits?)。

我们在此定义implicitInt实现Double,但它没有做任何事情。我们可以把这个类写成:

MyNumber

它按预期工作:

class Item[N : MyNumber](x: N) {
  def value: N = x
}

如果我们尝试在没有val iItem = new Item(1) val dItem = new Item(1.0) scala> iItem.value res1: Int = 1 scala> dItem.value res2: Double = 1.0 实例的情况下构建任何项目,则编译器会抛出错误:

MyNumber

如果您希望val sItem = new Item("S") error: could not find implicit value for evidence parameter of type MyNumber[String] 成为任何数字,Scala会实现MyNumber类型类。

修改

如果要为类型类添加一些针对每个数字不同的功能,可以执行以下操作:

Numeric