首页 文章

在函数中需要Scala隐式类

提问于
浏览
2

我的目标是为各种类型(时间戳,日期等)配备他们可能没有的默认属性(订购, - 等) . 我正在做这样的事情:

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 添加到double .

有没有办法将隐式类的证据传递给函数?或者,有更好的模式吗?

3 回答

  • 5

    @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
    }
    
  • 1

    你可以通过将 NiceProperties[T] 变成一个知道如何添加,总和......两个类型 T 的值来解决你的问题:

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

    您现在可以为Timestamps,Dates,...创建隐式 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

  • 3

    现有答案很好,但是,如果您无法修改特征,则可以将隐式转换作为参数:

    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
    

相关问题