【发布时间】:2019-02-04 09:30:45
【问题描述】:
提供的代码片段是一个虚构的简约示例,仅用于演示问题,与实际业务逻辑类型无关。
在下面的代码中,我们在Registry 类型中嵌套了一个Entry 类型。
class Registry[T](name: String) {
case class Entry(id: Long, value: T)
}
这是有道理的,因为不同注册表的条目是不同的、无与伦比的类型。
然后我们可能有一个隐式的 Ops 类,例如,在测试中使用,它将我们的注册表绑定到一些测试存储实现,一个简单的可变映射
object testOps {
import scala.collection.mutable
type TestStorage[T] = mutable.Map[Long, T]
implicit class RegistryOps[T](val self: Registry[T])(
implicit storage: TestStorage[T]
) {
def getById(id: Long): Option[self.Entry] =
storage.get(id).map(self.Entry(id, _))
def remove(entry: self.Entry): Unit = storage - entry.id
}
}
问题是:在 Ops 包装器内部构造的 Entry 被视为与原始 Registry 对象无法比拟的类型
object problem {
case class Item(name: String)
val items = new Registry[Item]("elems")
import testOps._
implicit val storage: TestStorage[Item] =
scala.collection.mutable.Map[Long, Item](
1L -> Item("whatever")
)
/** Compilation error:
found : _1.self.Entry where val _1: testOps.RegistryOps[problem.Item]
required: eta$0$1.self.Entry
*/
items.getById(1).foreach(items.remove)
}
问题是: 有没有办法声明 Ops 签名以使编译器了解我们正在使用相同的内部类型? (
我也试过 self.type#Entry 在 RegistryOps 没有运气)
如果我错过了一些理解并且它们实际上是不同的类型,我将不胜感激任何解释和示例,为什么将它们视为相同可能会破坏类型系统。谢谢!
【问题讨论】:
-
@jwvh 这将允许您混合和匹配来自不同注册表的条目,只要它们具有相同的
T,这会违背让Entry成为嵌套案例类的目的全部。
标签: scala inner-classes implicit scala-2.12