Требование неявного класса Scala в функции - PullRequest
0 голосов
/ 09 декабря 2018

Моя цель состоит в том, чтобы снабдить различные типы (метки времени, даты и т. Д.) Хорошими свойствами, которые они могут не иметь по умолчанию (упорядочение, - и т. Д.).Я делаю что-то вроде этого:

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 голосов
/ 09 декабря 2018

@ Ответ Аки полностью правильный.Вот только альтернативный подход, заключающийся в том, чтобы преобразовать его в рамки.Этот способ используется в 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
}
0 голосов
/ 09 декабря 2018

Существующие ответы хороши, но в тех случаях, когда вы не можете изменить черту, вам может потребоваться неявное преобразование в качестве параметра:

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
0 голосов
/ 09 декабря 2018

Вы можете решить вашу проблему, превратив 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

...