Использовать ограничения типов классов в выражении соответствия Scala - PullRequest
0 голосов
/ 07 февраля 2019

Я строю фабрику, которая производит экземпляр Product [T] для данного Config [T].Существует два типа конфигов:

trait Config[T]
case class SimpleConfig[T]() extends Config[T]
case class SpecialConfig[T <: Special]() extends Config[T]

Фабрика просто совпадает в конфигурации и делегирует двум подфабрикам:

def factory[T](config: Config[T]): Product[T] = config match {
  case c: SimpleConfig[_] => buildA[T](c)
  case sc: SpecialConfig[_] => buildASpecial[T](sc)
}

def buildA[X](c: Config[X]): Product[X] = ???
def buildASpecial[X <: Special](sc: SpecialConfig[X]): Product[X] = ???

Однако это не компилируется, потому что компилятор не можетубедитесь, что параметр типа конфигурации, переданный buildASpecial(), является подтипом Special.Похоже, что он может фактически проверить, что параметр sc является SpecialConfig[X] с X <: Special, но он не видит, что X на самом деле равен T, поэтому он может заключить, что T такжеSpecial.

Может быть, я что-то упустил, но вышеприведенная оценка мне кажется действительной.Можно ли это исправить без явного приведения?

1 Ответ

0 голосов
/ 07 февраля 2019

Предполагая, что Product и Config являются ковариантными, вы можете сделать следующее:

trait Special
trait Product[+T]

trait Config[+T]
case class SimpleConfig[T]() extends Config[T]
case class SpecialConfig[T <: Special]() extends Config[T]


def buildA[X](c: Config[X]): Product[X] = ???
def buildASpecial[X <: Special](sc: SpecialConfig[X]): Product[X] = ???

def factory[T](config: Config[T]): Product[T] = config match {
  case c: SimpleConfig[T] => buildA[T](c)
  case sc: SpecialConfig[t] => buildASpecial[t](sc)
}

В противном случае проблемы с подтипами в T <: Special не кажутся легко решаемыми путем сопоставления с образцом, и вместо этого нужно иметь дело с использованием старого доброго полиморфизма подкласса (в первую очередь вы выбрали для этого <:):

trait Special
trait Product[T]

trait Config[T] {
  def buildProduct: Product[T]
}
case class SimpleConfig[T]() extends Config[T] {
  def buildProduct = buildA[T](this)
}
case class SpecialConfig[T <: Special]() extends Config[T] {
  def buildProduct = buildASpecial[T](this)
}


def buildA[X](c: Config[X]): Product[X] = ???
def buildASpecial[X <: Special](sc: SpecialConfig[X]): Product[X] = ???

def factory[T](config: Config[T]): Product[T] = config.buildProduct
...