类层次结构上的算术

时间:2018-03-16 11:01:58

标签: scala generics types

如何对类型层次结构中包含的类进行算术运算?

我一直在尝试在摘要中存储不同类型的指标,以便我可以计算每个指标集合的聚合。

在下文中,我展示了我的实施尝试:
在我的第一次尝试中,我只使用了一个简单的类层次结构

sealed trait Metric {
  def getValue(): Number = ???
}
class Counter(count: Int) extends Metric {
  override def getValue() : Int = count
}
class Meter(rate: Double) extends Metric {
  override def getValue() : Double = rate
}

class Container(val key: String, x : Metric, val y : Metric) {
  // ERROR: Type mismatch expected: String actually: Number
  def combine(): Number = x.getValue + y.getValue
}

object Main {
  var list : List[Container] = List()
  var res : Map[String, Number] = list.map(x => x.key -> x.combine()).toMap
}

我的第二次尝试使用了泛型

sealed trait Metric2[M] {
  def getValue(): M = ???
}
class Counter2(count: Int) extends Metric2[Int] {
  override def getValue() : Int = count
}
class Meter2(rate: Double) extends Metric2[Double] {
  override def getValue() : Double = rate
}

class Container2[T](val key : String, x : Metric2[T], y: Metric2[T]) {
  // ERROR: Type mismatch expected: String actually: Number
  def combine(): T = x.getValue + y.getValue
}

object Main2 {
  var list2 : List[Container2[Number]] = List()
  var res : Map[String, Number] = list2.map(x => x.key -> x.combine()).toMap
}

错误在代码中突出显示。

据我所知,Number类实际上不是scala类型层次结构的一部分,而是使用Numeric。也许这是我的代码出错的地方。但是我找不到关于Numeric使用的好教程。任何提示都表示赞赏!

[编辑:]感谢Alexey Romanov的解决方案。我指定了容器的两个版本,一个带有implicts和context,另一个没有。

sealed abstract class Metric[M] {
  abstract def value(): M
}
class Counter(count: Int) extends Metric[Int] {
  override def value() : Int = count
}
class Meter(rate: Double) extends Metric[Double] {
  override def value() : Double = rate
}
class Container[T](val key : String, x : Metric[T], y: Metric[T])(implicit ev: Numeric[T]) {
  def combine(): T = implicitly[Numeric[T]].plus(x.value, y.value)
}
class Container2[T: Numeric](val key : String, x : Metric[T], y: Metric[T]) {
  import scala.Numeric.Implicits._
  def combine(): T = x.value + y.value
}
object Main {
  var list : List[Container[Number]] = List()
  var res : Map[String, Number] = list.map(x => x.key -> x.combine()).toMap
}

1 个答案:

答案 0 :(得分:3)

所需的修补程序非常小:

sealed abstract class Metric2[M: Numeric] {
  def getValue(): M
}
// no changes to Counter2 or Meter2

import scala.Numeric.Implicits._
class Container2[T: Numeric](val key : String, x : Metric2[T], y: Metric2[T]) {
  def combine(): T = x.getValue + y.getValue
}

: Numeric语法是context boundimport用于提供良好的运算符语法(如果没有它,则需要直接调用Numeric方法)。

作为旁注:

  1. getValue()应该是抽象的,允许您不实施此默认实施是有害的;

  2. 在没有括号的情况下调用value更好的Scala风格。