Может ли класс типа Scala иметь члены абстрактного типа? - PullRequest
0 голосов
/ 21 апреля 2019

У меня есть этот класс типов:

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

с экземпляром класса этого типа:

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

Но при попытке использовать экземпляр класса типа с чем-то вроде dbStringOps.isValidContent(newContent), где newcontentэто строка, я получаю несоответствие типов:

found   : newContent.type (with underlying type String)
required: database.DbOps.dbStringOps.R

Я могу заставить ее работать, преобразовав R из члена абстрактного типа в параметр типа, но это ужасно, так как R уже определено, когда я 'Я пишу реализацию класса типа.

Ответы [ 2 ]

7 голосов
/ 21 апреля 2019

добавить аннотации типа к этому implicit val.

implicit val dbStringOps: DbValueOps[DbString] { type R = String } = ...

или

получить неявный параметр, используя эту подпись.

def f()(implicit db: DbValueOps[DbString] { type R = String }) = ...

также можно написать так.

type AUX[A, T] = DbValueOps[A] { type R = T }

def f()(implicit db: AUX[DbString, String]) = ...
4 голосов
/ 21 апреля 2019

恵 砂 川 ответ решит вашу проблему отлично, но если вы действительно не хотите сосредоточить свой дизайн на DbValues, я предлагаю предложить вам неявное центрирование на обернутом значении (String в этом случае), так как вам не нужно предоставлятьобъединение R со String.

  trait DbValue[T]
  case class DbString(s:String) extends DbValue[String]


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

  object DbOps {
    val dbStringOps: DbOps[String] = new DbOps[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] = this(newContent)
      def isValidContent(newContent: String): Boolean = !newContent.isEmpty
    }

    val newContent = "hello"
    dbStringOps.isValidContent(newContent)
  }

Добавление параметра типа в DbValue может быть немного более многословным, но оно не позволяет вам определять такие вещи, как DbValueOps[DbString] { type R = Int }, что, вероятно, НЕ то, что вы ищете.

...