首页 > 解决方案 > 如何在需要具体类型的情况下使用具有存在类型的变量?

问题描述

这个人为的例子说明了我的问题的本质:

trait Producer[X] {def make(): X }

sealed trait MyProducer[X] extends Producer[X]
case class MyProducerA(n: Int) extends MyProducer[Int] {...}
case class MyProducerB(s: String) extends MyProducer[String] {...}

def doWithProducer[P <: Producer[_]](producer: P): P = {
  makePair(producer) // the compiler fails to infer the type parameter
  producer
}

def makePair[X](p: Producer[X]): (X, X) = (p.make(), p.make())

// this is how I need to call the method
val myProducer: MyProducer[_] = ???
doWithProducer(myProducer)

doWithProducer()方法不能具有产品类型的类型参数,因为子类型MyProducer具有不同的产品类型(或者我在这里已经错了吗?)。在里面doWithProduct()我知道我有一个具有类型参数的 Producer 的具体实例。我不在乎哪个,但它有一个。但是,编译器无法弄清楚这一点。

我可以在不更改方法签名的情况下解决这个问题吗?

更新:我觉得好奇并且让我假设必须有一种方法是我实际上可以在类型变量中间接捕获产品的类型:

def duplicate[X](p: X): (X, X) = (p, p)

duplicate(producer.make)

但是,我仍然无法获得Producer[X].

标签: scalatypesexistential-type

解决方案


P <: Producer[_]表示它P是某种未知类型的生产者。如果您想说它P是某个要推断的已知类型的生产者,则不应使用存在类型。

尝试

def doWithProducer[X, P <: Producer[X]](producer: P): P = {
  makePair(producer)
  producer
}

或者

def makePair(p: Producer[_]): (Any, Any) = (p.make(), p.make())

您必须更改至少一种方法的签名doWithProducer才能makePair使它们编译。

或者你可以投

def doWithProducer[P <: Producer[_]](producer: P): P = {
  makePair(producer.asInstanceOf[Producer[Any]]) 
  producer
}

推荐阅读