在函数中要求 Scala 隐式 class
Requiring Scala implicit class in a function
我的目标是为各种类型(时间戳、日期等)配备默认情况下可能没有的良好属性(排序、- 等)。我正在做这样的事情:
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
}
现在失败了,因为该函数缺少 class T
可以隐式向上转换为 NiceProperties[T]
的隐含证据,因此无法添加 (t + 1.0): T
加倍。
有没有办法将隐式 class 的证据传递给函数?或者,是否有更好的模式?
您可以通过将您的 NiceProperties[T]
变成一个 class 来解决您的问题,该 class 知道如何添加、求和...两个 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)
}
由于这很难看,您可以使用隐式 class 将 +
、-
、... 运算符添加到任何 class,其中隐式 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
}
@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
}
现有答案很好,但是,在您无法修改特征的情况下,您可以要求将隐式转换作为参数:
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
我的目标是为各种类型(时间戳、日期等)配备默认情况下可能没有的良好属性(排序、- 等)。我正在做这样的事情:
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
}
现在失败了,因为该函数缺少 class T
可以隐式向上转换为 NiceProperties[T]
的隐含证据,因此无法添加 (t + 1.0): T
加倍。
有没有办法将隐式 class 的证据传递给函数?或者,是否有更好的模式?
您可以通过将您的 NiceProperties[T]
变成一个 class 来解决您的问题,该 class 知道如何添加、求和...两个 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)
}
由于这很难看,您可以使用隐式 class 将 +
、-
、... 运算符添加到任何 class,其中隐式 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
}
@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
}
现有答案很好,但是,在您无法修改特征的情况下,您可以要求将隐式转换作为参数:
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