scala - 从具有参数化类型参数的另一个方法调用具有参数化类型参数的方法时保留特定的结果类型参数
问题描述
假设我正在尝试使用继承对实体、元数据和存储库进行建模
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
的东西。 - 我能做些什么来完成这项工作
解决方案
尝试修复签名
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[_]
inE[_] <: Entity[_]
不同:E[_]
是一个类型构造函数E[M]
(即每个类型都可以有一个类型M
),Entity[_]
也Entity[Meta] forSome { type Meta }
就是存在类型。存在类型没有.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
推荐阅读
- javascript - Does the classic copy to clipboard need input field/text area field necessarily?
- terraform - 如何使用 Terraform 将资源创建拆分为不同的模块?
- javascript - 在 const react native 中定义函数
- android - RxJava2-除非是TimeoutException,否则如何每次重试?
- c# - 有没有办法可以与 luis 链接对话
- jquery - 如何在以下函数中获取父元素id
- php - 在 Apache 服务器上查找特定目录
- karate - 无法根据需要转义 url
- session - 如何在 Asp.Net Core 2.2 中获取所有登录用户会话?
- php - 如何在字符串中输出 PHP 变量值以用作 MySQL 查询的一部分?