Невозможно сопоставить параметризованный тип с конкретным типом после сопоставления с образцом - PullRequest
0 голосов
/ 04 февраля 2019

При использовании scala 2.12.8 это не скомпилируется без приведения:

trait Content
case object A extends Content
case class B(i: Int) extends Content

def asList[C <: Content](content: C): List[C] = content match {
  case A => List(A) // compiles
  case b: B => List(b) // does not compile
}
type mismatch;
 found   : b.type (with underlying type Playground.this.B)
 required: C

Вот ссылка Scastie на проблему: https://scastie.scala -lang.org / JIziYOYNTwKoZpdCIPCvdQ

Почему работает для объекта case, а не для класса case?Как я могу заставить его работать для класса кейсов?

EDIT

Первые ответы заставили меня понять, что я упростил свою проблему, вот обновленная версия:

sealed trait Content
case object A extends Content
final case class B(i: Int) extends Content

sealed trait Container[+C <: Content]
case class ContainerA(content: A.type) extends Container[A.type]
case class ContainerB(content: B) extends Container[B]

object Container {
  def apply[C <: Content](content: C): Container[C] = content match {
    case A => ContainerA(A) // compiles
    case b: B => ContainerB(b) // does not compile
  }
}

Scastieссылка: https://scastie.scala -lang.org / TDlJM5SYSwGl2gmQPvKEXQ

C не может быть подтипом B, поскольку B является конечным.

Ответы [ 3 ]

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

Решение дано в комментарии @lasf:

def asList[C <: Content](content: C): List[C] = content match {
  case A => List(A) // compiles
  case b: B => List(content) // compiles
}

Проблема в том, что тип возвращаемого значения List[C], но компилятор не может гарантировать, что тип List(b) равен List[C],В частности, C может быть подтипом B, в этом случае List(b) будет List[B], который не совместим с List[C].


Обновленная версия может быть решена с использованием asInstanceOf, хотя это не красиво.

def apply[C <: Content](content: C): Container[C] = content match {
  case A => ContainerA(A) // compiles
  case b: B => ContainerB(b).asInstanceOf[Container[C]]
}

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

object Container {
  implicit def contain(content: A.type): Container[A.type] = ContainerA(content)
  implicit def contain(content: B): Container[B] = ContainerB(content)
}

val ca: Container[A.type] = A
val cb: Container[B] = B(0)

или даже несколько конструкторов:

object Container {
  def apply(content: A.type): Container[A.type] = ContainerA(content)
  def apply(content: B): Container[B] = ContainerB(content)
}

Вот альтернативный дизайн с использованием класса типов .Это заменит суперкласс Content на класс типов Containable.Класс Container теперь может содержать что угодно, если для этого класса существует экземпляр Containable.

case object A
case class B(i: Int)

sealed trait Container[C]
case class ContainerA(content: A.type) extends Container[A.type]
case class ContainerB(content: B) extends Container[B]

trait Containable[T] {
  def apply(value: T): Container[T]
}
object Containable {
  implicit object AContainer extends Containable[A.type] {
    def apply(value: A.type) = ContainerA(value)
  }
  implicit object BContainer extends Containable[B] {
    def apply(value: B) = ContainerB(value)
  }
}

object Container {
  def apply[C](content: C)(implicit containable: Containable[C]): Container[C] =
    containable(content)
}
0 голосов
/ 05 февраля 2019

C не может быть подтипом B, поскольку B является окончательным.

Неверно!

Синглтон-типы из B экземпляры являются подтипамииз B:

val b = B(0)
val container: Container[b.type] = Container[b.type](b)

Поскольку ContainerB не расширяет Container[b.type], он не может быть возвращен последней строкой.И это не может быть изменено так, чтобы это произошло:

case class ContainerB(content: B) extends Container[content.type]

недопустимо в Scala.

Null также является подтипом Bи вы можете создать аналогичный пример.Также как и типы уточнения, такие как B { type T = Int }.

Другие подтипы, которые, вероятно, не имеют значения, поскольку у них нет экземпляров: Nothing, составные типы, такие как B with Iterable[Int] ...

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

Причина, по которой вы получаете ошибку, заключается в том, что тип возвращаемого значения метода не является явным.Замена типа возвращаемого значения из List [C] в List [Content] решает проблему.

def asList[C <: Content](content: C): List[Content] = content match {
  case A => List(A) // compiles
  case b: B => List(b) // compiles
}
...