在函数中需要Scala隐式类

时间:2018-12-09 17:23:37

标签: scala implicit

我的目标是为各种类型(时间戳,日期等)配备默认情况下可能没有的漂亮属性(排序,-等)。我正在做这样的事情:

trait NiceProperties[T] {
  def -(t: T): Double
  def +(d: Double): T
  ...
}

implicit class BetterTimestamp(val t: Timestamp) extends NiceProperties[Timestamp] {
  override def -(Timestamp): ...
}

一切正常,直到我需要将其传递给假设NiceProperties的函数为止:

def myUtil[T](t: NiceProperties[T]): T = {
  (t + 1.0) + 1.0
}

这现在失败了,因为该函数缺少隐式证据,表明类T可以隐式地转换为NiceProperties[T],因此不能将(t + 1.0): T添加到双精度数中。

是否可以将隐式类的证据传递给函数?或者,是否有更好的模式呢?

3 个答案:

答案 0 :(得分:5)

您可以通过将NiceProperties[T]变成知道如何添加,求和……两个类型为T的值的类来解决问题:

trait NiceProperties[T] {
  def subtract(a: T, b: T): Double
  def add(a: T, d: Double): T
}

您现在可以为时间戳,日期等创建隐式NiceProperties对象或val

object BetterTimestamp extends NiceProperties[Timestamp] {
  def subtract(a: Timestamp, b: Timestamp): Double = ???
  def add(a: Timestamp, d: Double): Timestamp = ???
}

在示例方法中,您将请求隐式NiceProperties[T]来为您执行操作。

def myUtil[T](t: T)(implicit prop: NiceProperties[T]): T = {
  prop.add(prop.add(t, 1.0), 1.0)
}

由于这很丑陋,因此您可以使用隐式类将+-,...运算符添加到可使用隐式NiceProperties[T]的任何类中:

implicit class NicePropertiesOps[T](t: T)(implicit prop: NiceProperties[T]) {
  def +(d: Double): T = prop.add(t, d)
  def -(b: T): Double = prop.subtract(t, b)
}

现在,上面的示例几乎可以像您描述的那样工作。

def myUtil[T : NiceProperties](t: T): T = {
  (t + 1.0) + 1.0
}

https://scastie.scala-lang.org/0D1Y9sE5S5mrzm9coZPMWw

答案 1 :(得分:3)

@Aki的答案是完全正确的。这只是将转换纳入范围的另一种方法。在Numeric类型类中使用这种方式。

class Timestamp

trait NiceProperties[T] {
  def subtract(a: T, b: T): Double
  def add(a: T, d: Double): T

  implicit class Ops(t:T) {
    def +(d: Double): T = add(t, d)
    def -(b: T): Double = subtract(t, b)
  }

}

implicit object BetterTimestamp extends NiceProperties[Timestamp] {
  def subtract(a: Timestamp, b: Timestamp): Double = ???
  def add(a: Timestamp, d: Double): Timestamp = ???
}

def myUtil[T](t: T)(implicit prop: NiceProperties[T]): T = {
  import prop._
  (t + 1.0) + 1.0
}

和另一种有趣的方法。这是避免导入的方法:

trait NiceProperties[T] extends (T => Ops[T]) {
  def subtract(a: T, b: T): Double
  def add(a: T, d: Double): T

  implicit val v = this
  def apply(t:T) = new Ops(t)

}

class Ops[T](t:T)(implicit prop: NiceProperties[T]) {
  def +(d: Double): T = prop.add(t, d)
  def -(b: T): Double = prop.subtract(t, b)
}

implicit object BetterTimestamp extends NiceProperties[Timestamp] {
  def subtract(a: Timestamp, b: Timestamp): Double = ???
  def add(a: Timestamp, d: Double): Timestamp = ???
}

def myUtil[T:NiceProperties](t: T): T = {
  (t + 1.0) + 1.0
}

答案 2 :(得分:1)

现有的答案很好,但是,在无法修改特征的情况下,可以要求隐式转换作为参数:

def myUtil[T](t: T)(implicit conv: T => NiceProperties[T]) = t + 1.0 + 1.0

如果您经常这样做,则可以添加抽象类型,以便可以使用上下文绑定:

type HasNiceProperties[T] = T => NiceProperties[T]
def myUtil[T : HasNiceProperties](t: T) = t + 1.0 + 1.0