2013-12-09 72 views
2

我有案例类和每个案例类T我定义一个实体[T]隐式。这些情况下定义一个ID类型是特定于每个T.我然后定义一个抽象表[T]类与检索方法,该方法通过一个投影型T中定义的ID类型的标识符...如何在方法参数中使用泛型类型投影?

但它不工作,我得到类型不匹配:

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 

trait Entity[T] { 
    type Id 
    type Key 
    def getId(entity: T): Id 
    def keyFromId(id: Id): Key 
} 

case class A(f1: String, f2: Int) 

object AImplicits { 
    implicit object AEntity extends Entity[A] { 
    type Id = String 
    type Key = UUID 
    def getId(entity: A) = entity.f1 
    def keyFromId(id: String) = UUID.fromString(id) 
    } 
} 

object Main { 
    abstract class Table[T: Entity] { 
    def store(entity: T): Unit 
    def retrieve(id: Entity[T]#Id): Option[T] 
    } 

    def makeTable[T: Entity]: Table[T] = 
    new Table[T] { 
     def store(entity: T): Unit = {} 
     def retrieve(id: Entity[T]#Id): Option[T] = { 
     val key = implicitly[Entity[T]].keyFromId(id) // Type mismatch on 'id'. 
     None 
     } 
    } 

    def main(args: Array[String]) { 
    import AImplicits._ 
    val t = makeTable[A] 
    val a = A("dummy", 9) 
    t.store(a) 
    t.retrieve("dummy") // Type mismatch on "dummy". 
    } 
} 

任何帮助将是非常赞赏。

+1

'def'(实体:E)中的'E':Unit' – stew

+0

对不起,这是一个混淆。应该没有Es,只有Ts。我编辑了代码。谢谢。 – distfp

回答

0

当您扩展上下文绑定速记时,类型不匹配更容易看到。请记住,[T : Entity]语法只是需要暗示Entity[T]在范围内的语法糖。所以你makeTable功能的标题居然是:

​​

现在用的范围内隐参数,你implicitly呼叫功能将抓住这个值(实际上是new Table[T]构造抓住隐,然后implicitly抓住它从那里),所以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 
    } 
    } 

注意,没有转换发生用于retrieveid参数的类型声明。本质上,编译器抱怨entity.keyFromId期望entity.Id类型的参数,但您的id参数是抽象类型Entity[T]#Id

这里的问题是,你想要隐藏EntityTable类的用户的ID,但你想在其中一种方法中公开Id的类型。假设我有两个Table[T]实例,但它们使用不同的Entity[T]实现 - 不同的是它们的Id类型实际上是不同的。表实例的用户如何知道要传递给retrieve函数的类型?您可以通过向Table类添加另一个类型参数来解决此问题。你仍然可以抽象掉的ID /密钥生成逻辑,但是这将让编译器类型检查,以确保retrieve功能获得正确类型的参数。

+0

你说得对,它是一个路径依赖型问题。我的问题是制定很差,因为我实际上是寻找一个解决方案,使隐含参数的类型相匹配的抽象类(在型投影)......我终于找到了一种方法,通过使用早期的初始化和抽象的VAL设置为隐含对象。接受你的答复作为答案。 – distfp

相关问题