Как я могу указать, что у класса, переданного в параметре типа, есть определенный объект-компаньон? - PullRequest
0 голосов
/ 20 апреля 2019

У меня есть две эти черты:

sealed trait DbValue {
  type R
  type T <: DbValue
  def content(): R
  def copy(newContent: R = content): Option[T]
  def toString(): String
}

sealed trait DbValueOps {
  type R
  type T <: DbValue
  def apply(newContent: R): Option[T]
  def fromString(newContent: String): Option[T]
  def isValidContent(newContent: R): Boolean
}

и хотят создать метод / класс, который принимает объекты, которые реализуют обе черты, однако DbValue реализуется классом, а DbValueOps реализуется объектом-компаньоном.

Пример:

case class Column[T <: DbValue with DbValueOps] (val name: String, val cells: Vector[Option[T]] = Vector(), val blank_allowed: Boolean = true) {}

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

case class DbString private (val content: String) extends DbValue {
  type R = String
  type T = DbString
  def copy(newContent: String = content): Option[DbString] = DbString(newContent)
  override def toString(): String = content
}

object DbString extends DbValueOps {
  type R = String
  type T = DbString
  def apply(newContent: String): Option[DbString] =
    isValidContent(newContent) match {
      case true => Some(new DbString(newContent))
      case false => None
    }
  def fromString(newContent: String): Option[DbString] = DbString(newContent)
  def isValidContent(newContent: String): Boolean = !newContent.isEmpty
}

Однако, когда я пытаюсь создать такую ​​колонку, с: Column[DbString]("name") Я получаю ошибку: type arguments [database.DbString] do not conform to method apply's type parameter bounds [T <: database.DbValue with database.DbValueOps]

Есть ли хороший способ сделать это? Или как мне изменить свой дизайн?

Ответы [ 2 ]

2 голосов
/ 20 апреля 2019

Класс X и его сопутствующий объект X совершенно не связаны с точки зрения ООП (за исключением того, что их члены "могут видеть" друг друга, даже если они являются частными).Тип класса X равен X, тип объекта X равен X.type и эти типы также не связаны.

Попробуйте

case class Column[T <: DbValue, U <: DbValueOps](...

Column[DbString, DbString.type]("name")
0 голосов
/ 03 мая 2019

Вот как я решил эту проблему:

Черты, реализованные объектом, и черта ops создаются тем, что, как я считаю, называется экземпляром класса типов.

sealed trait DbValue[R, T <: DbValue[R, T]] {
  def content(): R
  def copy(newContent: R = content): Option[T]
  def toString(): String
}

sealed trait DbValueOps[R, T <: DbValue[R, T]] {
  def apply(newContent: R): Option[T]
  def fromString(newContent: String): Option[T]
  def isValidContent(newContent: R): Boolean
  def fromDbValue[U, V <: DbValue[U, V]](dbValue: V): Option[T] = fromString(dbValue.toString())
}

и тогда мой столбец просто принимает экземпляр класса типа в качестве параметра (в данном случае неявный, но, вероятно, это не очень хорошая вещь в этом сценарии).Система типов гарантирует, что объект класса типов связан с объектом DbValue.

case class Column[R, T <: DbValue[R, T]] private (
  val name: String,
  val cells: Vector[Option[T]] = Vector(),
  val blankAllowed: Boolean = true,
  val defaultValue: Option[T] = None,
  )(implicit ops: DbValueOps[R, T]) extends ColumnStringOps {
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...