如何在方法参数中使用泛型投影? [英] How do I use a generic type projection in a method parameter?

查看:126
本文介绍了如何在方法参数中使用泛型投影?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有案例类,对于每个案例类我定义了一个实体[T]隐式。这些实例定义了一个特定于每个T的Id类型。然后用一个检索方法定义一个抽象Table [T]类,该方法通过类型投影来获取T中定义的Id类型的标识符...



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

  scalac generic-type- projection.scala 
generic-type-projection.scala:31:error:type mismatch;
found:id.type(带底层类型实体[T] #Id)
required:_5.Id其中val _5:Entity [T]
val key =隐式[Entity [T] ] .keyFromId(id)//在'id'上输入不匹配。
^
generic-type-projection.scala:41:error:type mismatch;
found:String(dummy)
required:实体[A] #Id
t.retrieve(dummy)
^
找到两个错误

以下是代码:

  import java.util.UUID 

trait实体[T] {
类型Id
类型键
def getId (实体:T):Id
def keyFromId(id:Id):Key
}

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

object AImplicits {
隐式对象AEntity extends实体[A] {
类型Id =字符串
类型键= UUID
def getId(entity:A)= entity.f1
def keyFromId(id:String)= UUID.fromString(id)
}
}

对象Main {
抽象类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 =隐式地[Entity [T]]。keyFromId(id)//在'id'上输入不匹配。
None



def main(args:Array [String]){
import AImplicits._
val t = makeTable [a]
val a = A(dummy,9)
t.store(a)
t.retrieve(dummy)//输入dummy不匹配。
}
}

任何帮助都将非常感谢。

解决方案

当扩展上下文绑定速记时,类型不匹配更容易看到。请记住, [T:Entity] 语法只是需要隐含 Entity [T] 的语法糖范围。所以你的 makeTable 函数的头部其实是:

  def makeTable [ T](隐式实体:实体[T]):Table [T] = 

参数在函数中,函数中的隐含调用将获取该值(实际上, new Table [T] 构造函数抓取隐式,然后隐式地从那里抓取它),所以 makeTable 函数的展开形式为:

  def makeTable [T](隐式实体:实体[T]):Table [T] = 
new Table [T ] {
def store(entity:T):Unit = {}
def retrieve(id:Entity [T] #Id):Option [T] = {
val key = entity。 keyFromId(id)//在'id'上键入不匹配。



$ / code $ / pre

请注意,没有转换发生 id 参数检索的类型声明。实质上,编译器抱怨 entity.keyFromId 期望类型为 entity.Id 的参数,但是您的 id 参数是抽象类型实体[T] #Id



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

I have case classes and for each case class T I define an Entity[T] implicit. These instances define an Id type that is specific to each T. I then define an abstract Table[T] class with a retrieve method that takes an identifier of the Id type defined in T through a type projection...

But it does not work, I get type mismatches:

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

Here's the code:

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".
  }
}

Any help would be very much appreciated.

解决方案

The type mismatch is a bit easier to see when you expand the context bound shorthand. Remember, the [T : Entity] syntax is just syntactic sugar for requiring an implicit Entity[T] to be in scope. So the header of your makeTable function is actually:

def makeTable[T](implicit entity: Entity[T]): Table[T] =

Now with that implicit parameter in scope, your implicitly call in the function will grab that value (actually, the new Table[T] constructor grabs the implicit, and then implicitly grabs it from there), so the makeTable function in its expanded form:

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
    }
  }

Notice that there is no conversion taking place for the type declaration of the id parameter of retrieve. Essentially, the compiler is complaining that entity.keyFromId is expecting a parameter of type entity.Id, but your id parameter is of the abstract type Entity[T]#Id.

The problem here is that you want to hide the Entity and the ids from users of the Table class, yet you want to expose the type of the Id in one of the methods. Suppose I have two instances of Table[T], but they use different Entity[T] implementations -- so different that their Id types are actually different. How would the users of the table instances know which type to pass to retrieve functions? You could fix this by adding another type parameter to the Table class. You can still abstract away the id/key generation logic, but this will allow the compiler to type check to make sure the retrieve function is getting the right type of parameter.

这篇关于如何在方法参数中使用泛型投影?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆