我有两个特征:
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]
有没有很好的方法可以做到这一点?还是应该更改设计?
答案 0 :(得分:2)
从OOP的角度来看,类X
及其伴随对象X
完全不相关(除非它们的成员“彼此可见”,即使它们是私有的)。类X
的类型为X
,对象X
的类型为X.type
,并且这些类型也不相关。
尝试
case class Column[T <: DbValue, U <: DbValueOps](...
Column[DbString, DbString.type]("name")
答案 1 :(得分:0)
这就是我最终解决它的方式:
特征由一个对象实现,而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())
}
,然后我的列仅将类型类实例作为参数(在这种情况下为隐式实例,但这在这种情况下可能不是一件好事)。类型系统强制将typeclass对象与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 {