【问题标题】:Scala - overloading operators for custom wrappersScala - 自定义包装器的重载运算符
【发布时间】:2016-05-03 03:02:04
【问题描述】:

我想要一个练习来创建某种幺半群,即。通用类型的自定义包装类,允许我调整它们的基本操作:

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[_])

现在我有一个函数,它根据参数返回带有签名的条目类型(始终具有相同的值类型,即 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[_]] 类型。

关于如何“以正确的方式”解决此问题的任何提示?

【问题讨论】:

  • 我可以将 Entry 参数化为Entry[T](bucket: Integer, value: WrappedVal[T]),但我只能在运行时告诉 readValue 的返回类型,这会导致所有混乱 - readValue 返回 WrappedValue[_]。

标签: scala types functional-programming


【解决方案1】:

我在你的代码上玩了一下,然后让它工作了

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[_]) 方法,有点丑。

希望它可以帮助您找到“正确的方法”

【讨论】:

    【解决方案2】:

    现在我有一个函数,它根据参数返回条目类型(始终具有相同的值类型,即 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 }

    【讨论】:

      猜你喜欢
      • 2017-02-22
      • 2017-11-04
      • 1970-01-01
      • 2013-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多