Может ли компилятор Scala понимать переопределенные абстрактные типы - PullRequest
0 голосов
/ 18 февраля 2020

Контекст:

Я пытаюсь использовать полиморфизм c подтипа, предоставленного Джексоном, JsonSubTypes, в конечной точке RESTful. Существует некоторая общность между различными телами запросов, поэтому у меня есть:

abstract class A extends Translatable {
  val infoA: String
  val infoB: String
}

case class B(
  infoA: String,
  infoB: String,
  infoC: String,
  infoD: Int
) extends A {
  override type T = B
  def translate(
    requestInfo: String,
    request: B
  ): String = s"<$infoA,$infoB>:$infoC-${infoD.toString}"
}


case class C(
  infoA: String,
  infoB: String,
  infoC: Array[String]
) extends A {
  override type T = C
  def translate(
    requestInfo: String,
    request: C
  ): String = s"<$infoA,$infoB>:${infoC.mkString}"
}

со следующей чертой, чтобы без необходимости сопоставлять входящий запрос A с B или C:

trait Translatable {
  type T <: A
  def translate(
    requestInfo: String,
    request: T
  ): String
}

проблема в том, что, когда я компилирую, он жалуется на несоответствие типов:

found: request.type (with underlying type com.program.A)
required: request.T

Я пробовал несколько вещей, но безрезультатно, только с этим, казалось бы, близко:

  • неявные ограничения обобщенного типа
e.g.,
def translate[X](
  requestInfo: String,
  request: X
)(implicit ev: X <:< A) = ...
(modifying the case class impl. of ^ accordingly)

, но это приводит к

Невозможно доказать, что com.program.A <: <request. T </p>

Есть мысли о том, как это сделать? Или я должен просто терпеть совпадение шаблонов? Я говорю, потому что первый блок кода работает тогда, когда я сопоставляю шаблон и вызываю конкретный импл. translate для B или C, но я бы предпочел иметь параметр типа A и вызывать translate. Возможно ли это?

РЕДАКТИРОВАТЬ: Добавление случаев, когда вышеизложенное приводит к ошибкам компиляции:

class Program {
  def doWork(
    info: String,
    request: A
  ): String = {
    request.translate(
      info,
      request // compilation fails/complains about this param in both cases
    )
  }
}

РЕДАКТИРОВАНИЕ2: Добавление квалификации: мне нужно переопределить типы в подтипах, B & C, так что в переводе весело c. Я могу назвать поля, указанные c B или C

1 Ответ

3 голосов
/ 18 февраля 2020

Попробуйте добавить параметр типа с уточненной верхней границей

def doWork[T0 <: A { type T = T0 }](
            info: String,
            request: T0
          ): String = {
  request.translate(
    info,
    request
  )
}

doWork("info1", B("infoA1", "infoB1", "infoC1", 1))//<infoA1,infoB1>:infoC1-1
doWork("info2", C("infoA2", "infoB2", Array("infoC21", "infoC22")))//<infoA2,infoB2>:infoC21infoC22
...