简体   繁体   English

类层次结构上的算法

[英]Arithmetics on a class hierarchy

How can I do arithmetics on classes included in a type hierarchy? 如何对类型层次结构中包含的类进行算术运算?

I have been trying to store different types of metrics in summaries, so that I could compute aggregates on each metric collection. 我一直在尝试在摘要中存储不同类型的指标,以便可以在每个指标集合上计算聚合。

In the following I show my attempts at implementation: 下面,我展示了我的实现尝试:
In my first attempt I used only a simple class hierarchy 在我的第一次尝试中,我仅使用了简单的类层次结构

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
}

My second attempt used generics 我第二次尝试使用泛型

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
}

The errors are highlighted in the code. 错误在代码中突出显示。

To my understanding the Number class is not actually part of the scala type hierarchy and instead Numeric shoud be used. 据我了解,Number类实际上并不是scala类型层次结构的一部分,而应使用Numeric。 Maybe this is the place where my code takes a wrong turn. 也许这是我的代码转错了地方。 However I could not find a good tutorial on the usage of Numeric. 但是我找不到关于数字用法的很好的教程。 Any hints are appreciated! 任何提示表示赞赏!

[EDIT:] Thanks to Alexey Romanov for the solution. [编辑:]感谢Alexey Romanov的解决方案。 I specified two versions of the container, one with implicts and context and one without. 我指定了容器的两个版本,一个带有隐式和上下文,另一个没有。

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
}

The fixes required are pretty small: 所需的修复很小:

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
}

The : Numeric syntax is a context bound and the import is used to provide the nice operator syntax (you would need to call the Numeric methods directly without it). : Numeric语法是上下文绑定的 ,并且import用于提供不错的运算符语法(如果没有,则需要直接调用Numeric方法)。

As a side note: 附带说明:

  1. getValue() should be abstract, this default implementation is actively harmful by allowing you not to implement it; getValue()应该是抽象的,此默认实现会因不允许您不实现而对它有害。

  2. it's better Scala style to call it value without parentheses. 最好使用Scala样式来将其命名为不带括号的value

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

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