Scala - 为自定义包装器重载运算符

时间:2016-01-26 14:06:37

标签: scala types functional-programming

我想要练习创造某种幺半群,即。常用类型的自定义包装类,允许我对它们进行基本操作:

abstract class WrappedVal[T](value: T) {
  def +(that: WrappedVal[T]): WrappedVal[T]
  def get: T = value
}

case class NumericValue(value: Double) extends WrappedVal[Double](value) {
  override def +(that: WrappedVal[Double]): NumericValue = NumericValue(value + that.get)
}

case class StringValue(value: String) extends WrappedVal[String](value) {
  override def +(that: WrappedVal[String]): StringValue = StringValue(value.substring(1) + that.get.substring(1))
}

通过这种方式,我可以做NumericValue(3)+NumericValue(4)并获得NumericValue(7)

然后我想更多地包装这个值,所以我补充说:

case class Entry(bucket: Integer, value: WrappedVal[_])

现在我有一个函数,根据params返回Entry类型(它们总是具有相同的值类型,即NumericValue或StringValue或SomeOtherValue)和签名:

def readValue(vartype: String, value: String): WrappedVal[_] = {
    if(vartype == "String") StringValue(value)
    else NumericValue(value.toInt)
}

如此有效地得到:

val l = List(Entry(1,NumericValue(1)), Entry(1,NumericValue(2)), Entry(1,NumericValue(3)))

当我想使用我的自定义运算符时出现问题,例如在reduce子句中:

l.map(x => x.value).reduce(_+_)

这是因为scala可以在运行时找出类型(l.map(x => x.value)属于List[WrappedVal[_]]类型。

有关如何解决此问题的任何提示'正确的方式'?

2 个答案:

答案 0 :(得分:0)

我正在玩你的代码,并让它工作

abstract class WrappedVal[T](value: T)(implicit A: ClassTag[T]) {
  def +(that: WrappedVal[_]): WrappedVal[T] = {
    classTag[T] match {
      case t if t == classTag[String] => StringValueFunctions.add(this.asInstanceOf[WrappedVal[String]], that.asInstanceOf[WrappedVal[String]]).asInstanceOf[WrappedVal[T]]
      case t if t == classTag[Double] => NumericValueFunctions.add(this.asInstanceOf[WrappedVal[Double]], that.asInstanceOf[WrappedVal[Double]]).asInstanceOf[WrappedVal[T]]
    }
  }
  def get: T = value
}

case class NumericValue(value: Double) extends WrappedVal[Double](value)
case object NumericValueFunctions {
  def add(value:WrappedVal[Double], that: WrappedVal[Double]): WrappedVal[Double] = NumericValue(value.get + that.get)
}

case class StringValue(value: String) extends WrappedVal[String](value) 
case object StringValueFunctions{
  def add(value: WrappedVal[String], that: WrappedVal[String]): WrappedVal[String] = StringValue(value.get.substring(1) + that.get.substring(1))
}

如果您希望此l.map(x => x.value).reduce(_+_)能够工作 你需要一个def +(that: WrappedVal[_])方法,这有点难看。

希望它能帮助您找到正确的方法'

答案 1 :(得分:0)

  

现在我有一个函数,取决于params返回Entry类型(它们总是具有相同的值类型,即NumericValue或StringValue或SomeOtherValue)

问题是编译器不知道这一点。您可以将readValue来电分组来表达吗?即。

case class Entries[T](entries: List[Entry[T]]) {
  def sum = entries.map(_.value).reduce(_ + _)
}

def readValues(...): Entries[_]

或者,如果您不想引入Entries类型,则可以使用存在感:List[Entry[T]] forSome { type T }