Scala 如何在方法参数中使用泛型类型投影?
我有案例类,对于每个案例类T,我定义一个实体[T]隐式。这些实例定义了一个特定于每个T的Id类型。然后,我使用一个检索方法定义了一个抽象表[T]类,该方法通过类型投影获取T中定义的Id类型的标识符 但它不起作用,我得到类型不匹配:Scala 如何在方法参数中使用泛型类型投影?,scala,generics,types,projection,Scala,Generics,Types,Projection,我有案例类,对于每个案例类T,我定义一个实体[T]隐式。这些实例定义了一个特定于每个T的Id类型。然后,我使用一个检索方法定义了一个抽象表[T]类,该方法通过类型投影获取T中定义的Id类型的标识符 但它不起作用,我得到类型不匹配: scalac generic-type-projection.scala generic-type-projection.scala:31: error: type mismatch; found : id.type (with underlying type
scalac generic-type-projection.scala
generic-type-projection.scala:31: error: type mismatch;
found : id.type (with underlying type Entity[T]#Id)
required: _5.Id where val _5: Entity[T]
val key = implicitly[Entity[T]].keyFromId(id) // Type mismatch on 'id'.
^
generic-type-projection.scala:41: error: type mismatch;
found : String("dummy")
required: Entity[A]#Id
t.retrieve("dummy")
^
two errors found
代码如下:
import java.util.UUID
特质实体[T]{
类型Id
类型键
def getId(实体:T):Id
def keyFromId(id:id):密钥
}
案例类别A(f1:String,f2:Int)
对象对象对象{
隐式对象实体扩展实体[A]{
类型Id=字符串
类型Key=UUID
def getId(实体:A)=实体.f1
def keyFromId(id:String)=UUID.fromString(id)
}
}
对象主体{
抽象类表[T:实体]{
def存储(实体:T):单位
def检索(id:Entity[T]#id):选项[T]
}
def makeTable[T:实体]:表[T]=
新表格[T]{
def存储(实体:T):单位={}
def检索(id:实体[T]#id):选项[T]={
val key=隐式地[Entity[T]]。keyFromId(id)//id上的类型不匹配。
没有一个
}
}
def main(参数:数组[字符串]){
导入AImplicits_
val t=可生成表[A]
val a=a(“虚拟”,9)
t、 商店(a)
t、 检索(“dummy”)//在“dummy”上的类型不匹配。
}
}
非常感谢您的帮助。当您扩展上下文绑定速记时,类型不匹配更容易看到。请记住,
[T:Entity]
语法只是要求隐式实体[T]
在范围内的语法糖。因此,makeTable
函数的标题实际上是:
def makeTable[T](implicit entity: Entity[T]): Table[T] =
现在有了作用域中的隐式参数,函数中的隐式
调用将获取该值(实际上,新表[T]
构造函数获取隐式,然后隐式
从那里获取它),因此makeTable
函数以其扩展形式:
def makeTable[T](implicit entity: Entity[T]): Table[T] =
new Table[T] {
def store(entity: T): Unit = {}
def retrieve(id: Entity[T]#Id): Option[T] = {
val key = entity.keyFromId(id) // Type mismatch on 'id'.
None
}
}
请注意,retrieve
的id
参数的类型声明没有进行转换。本质上,编译器抱怨entity.keyFromId
需要类型为entity.Id
的参数,但是Id
参数是抽象类型entity[T]#Id
这里的问题是,您想对
表
类的用户隐藏实体
和Id,但您想在其中一个方法中公开Id的类型。假设我有两个表[T]
的实例,但它们使用不同的实体[T]
实现——它们的Id
类型实际上是不同的。表实例的用户如何知道传递给retrieve
函数的类型?您可以通过向表
类添加另一个类型参数来解决此问题。您仍然可以抽象出id/密钥生成逻辑,但这将允许编译器进行类型检查,以确保retrieve
函数获得正确类型的参数。在def store(entity:E):Unit
中E
是什么。应该没有Es,只有Ts。我编辑了代码。谢谢。你说得对,这是一个路径依赖型问题。我的问题表述得很糟糕,因为我实际上在寻找一种解决方案,使隐式参数的类型与抽象类型匹配(在类型投影中)。。。我最终找到了一种方法,使用一个早期的初始值设定项,将抽象val设置为隐式对象。接受你的回答。