我已经创建了下面的人为例子来展示我想要完成的事情。我正在寻找一个工厂,它会吐出一个类,该类通过它将处理的特定类型的请求进行参数化。我以为我理解了仿制药,但现在我怀疑自己。 :)
object SourceFactory {
def apply[T <: Source[_ <: RequestContext]](x: String): Source[_ <: RequestContext] = {
x match {
case "a" => new FooSource
}
}
}
object RequestContextFactory {
def apply[T >: RequestContext](x: String): T = {
x match {
case "a" => FooRequestContext()
}
}
}
abstract class RequestContext
case class FooRequestContext() extends RequestContext
abstract class Source[T <: RequestContext] {
def get(ctx: T): Unit
}
class FooSource extends Source[FooRequestContext] {
def get(ctx: FooRequestContext): Unit = {}
}
object Test extends App {
val source = SourceFactory("a")
val ctx = RequestContextFactory("a")
source.get(ctx)
}
结果:
编译器异常错误:第32行:类型不匹配; 发现:Evaluator__da15fb805d29b29227bc28ccae6cd07d2c04cb40_1274353927.Test.ctx.type(底层类型为RequestContext) 必需:_ $ 2 source.get(CTX)
提前感谢您的帮助!
答案 0 :(得分:1)
Scala无法在T
或SourceFactory.apply
中推断RequestContextFactory.apply
,因为它不会出现在参数中。您正在呼叫SourceFactory[Nothing]
和RequestContextFactory[RequestContext]
(仅次于def apply[T >: RequestContext]
中可能的拼写错误)。
您可以明确地提供T
:
object SourceFactory {
def apply[T <: RequestContext](x: String): Source[T] = {
(x match {
case "a" => new FooSource
}).asInstanceOf[Source[T]]
}
}
object RequestContextFactory {
def apply[T <: RequestContext](x: String): T = {
(x match {
case "a" => FooRequestContext()
}).asInstanceOf[T]
}
}
object Test extends App {
val source = SourceFactory[FooRequestContext]("a")
val ctx = RequestContextFactory[FooRequestContext]("a")
source.get(ctx)
}
注意你最终需要演员表:这应该暗示这是一个糟糕的设计!问题是您的返回类型取决于参数的值。 Scala确实支持这种称为路径依赖类型的形式,但它不适用于此处。您还可以尝试删除类型参数并仅使用存在性:
object SourceFactory {
def apply(x: String): Source[_ <: RequestContext] = {
x match {
case "a" => new FooSource
}
}
}
object RequestContextFactory {
def apply(x: String): RequestContext = { // equivalent to _ <: RequestContext
x match {
case "a" => FooRequestContext()
}
}
}
object Test extends App {
val source = SourceFactory("a")
val ctx = RequestContextFactory("a")
source.get(ctx)
}
SourceFactory
或ResourceContextFactory
中没有演员表,但他们的返回类型之间也没有任何关系,所以source.get(ctx)
将无法编译!
根据您的要求,实际可行的是将返回值配对为单一类型:
case class SourceAndRequestContext[T <: RequestContext](src: Source[T], ctx: T) {
def get() = src.get(ctx)
}
object SourceAndRequestContextFactory {
def apply(x: String): SourceAndRequestContext[_ <: RequestContext] = x match {
case "a" => SourceAndRequestContext(new FooSource, FooRequestContext())
}
}