假设我正在尝试使用继承为实体,元数据和存储库建模
trait EntityMetadata {
def maybeVersion: Option[Int]
}
// For creation
case object NoMetadata extends EntityMetadata {
def maybeVersion: Option[Int] = None
}
// For other cases
final case class VersionedMetadata(version: Int) extends EntityMetadata {
def maybeVersion: Option[Int] = Some(version)
}
trait Entity[Meta <: EntityMetadata] {
type Id
def id: Id
def meta: Meta // Meta is paremeterised
}
如果我随后尝试创建一个特征以容纳通用后备存储的某些方法,即使类型类型已知,我似乎也喜欢...我实际上无法正确使用它们吗?
trait BackingStore {
// Method for retrieving an entity by id
// `Meta` doesn't really matter here, but we can't
// wild-card it. We return the Entity with VersionedMetadata
// since it's been stored if we can find it
def getFromStore[Meta <: EntityMetadata, E[_] <: Entity[_]](
id: E[Meta]#Id
): Option[E[VersionedMetadata]]
// Just for demo purposes, try to retrieve something by id
// and return its metadata version
def getVersion[Meta <: EntityMetadata, E[_] <: Entity[_]](
id: E[Meta]#Id
): Option[Long] = getFromStore(id).map { retrieved =>
// So far so good, we know it's E[VersionedMetadata]
val typeTest: E[VersionedMetadata] = retrieved
//
// value version is not a member of _$2
// typeTest.meta.version // complains about version
//
retrieved.meta.version // complains about version
}
}
我正在尝试:
retrieved.meta
没有.version
,或者实际上没有任何Any
/ Object
拥有的东西。答案 0 :(得分:2)
尝试修复签名
def getFromStore[Meta <: EntityMetadata, E[M <: EntityMetadata] <: Entity[M]](
id: E[Meta]#Id
): Option[E[VersionedMetadata]]
def getVersion[Meta <: EntityMetadata, E[M <: EntityMetadata] <: Entity[M]](
id: E[Meta]#Id
): Option[Long]
E[_]
和Entity[_]
中的E[_] <: Entity[_]
是不同的:E[_]
是type constructor(即每种类型都可以有类型E[M]
M
),又称Entity[_]
Entity[Meta] forSome { type Meta }
是existential type。现有类型没有.version
(retrieved.meta
的类型为Any
)。
另一种修复代码的方法是
def getFromStore[Meta <: EntityMetadata, E[_] <: Entity[_]](
id: E[Meta]#Id
): Option[E[VersionedMetadata]]
def getVersion[Meta <: EntityMetadata, E[_] <: Entity[_ <: EntityMetadata]](
id: E[Meta]#Id
): Option[Int] = getFromStore(id).flatMap { retrieved =>
val typeTest: E[VersionedMetadata] = retrieved
retrieved.meta.maybeVersion
}
我保留了类型构造函数和存在性类型,但在存在性类型<: EntityMetadata
的参数中添加了上限Entity[_ <: ...]
,这是类型参数E[_] <: ...
的上限。现在retrieved.meta
的类型是EntityMetadata
的子类型,因此它具有.maybeVersion
而不是.version
(并且map
应该替换为flatMap
) 。同样,Long
也应替换为Int
。
或者您可以将上限_ <: VersionedMetadata
代替我的<: EntityMetadata
。然后,您可以保留.version
,.map
和Long
。