【问题标题】:How can I specify that a class passed in a type parameter has a certain companion object?如何指定传入类型参数的类具有某个伴生对象?
【发布时间】:2019-09-10 04:37:40
【问题描述】:

我有这两个特点:

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 &lt;: database.DbValue with database.DbValueOps]

有什么好办法吗?或者我应该如何改变我的设计?

【问题讨论】:

    标签: scala generics polymorphism traits companion-object


    【解决方案1】:

    类X 和它的伴生对象X 从OOP 的角度来看是完全不相关的(除了它们的成员“可以看到”彼此,即使它们是私有的)。 X 的类类型是X,X 的对象类型是X.type,这些类型也不相关。

    试试

    case class Column[T <: DbValue, U <: DbValueOps](...
    
    Column[DbString, DbString.type]("name")
    

    【讨论】:

    【解决方案2】:

    这就是我最终解决它的方式:

    trait 是由对象实现的,而 ops trait 由我相信的类型类实例实例化。

    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 {
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-19
      • 1970-01-01
      • 1970-01-01
      • 2020-02-21
      • 1970-01-01
      • 2020-03-11
      相关资源
      最近更新 更多