jde*_*lop 0 scala type-inference covariance
鉴于代码
object Renderer {
sealed abstract class BasicRender
case class RenderImages(img: Array[File]) extends BasicRender
case class RenderVideo(video: File) extends BasicRender
def rendererFor[T <: BasicRender : Manifest, Z <: Render.RenderingContext](ctx: Z): Option[Render[T]] = {
val z = manifest[T].erasure
if (z == classOf[RenderImages]) {
Some(new ImagesRenderer(ctx.asInstanceOf[ImagesContext])) // .asInstanceOf[Render[T]])
} else
if (z == classOf[RenderVideo]) {
Some(new VideoRenderer(ctx.asInstanceOf[VideoContext])) // .asInstanceOf[Render[T]])
} else {
None
}
}
private class ImagesRenderer(ctx: ImagesContext) extends Render[RenderImages] {
override def renderJSON(json: String)(implicit jsCtx: PhantomJsContext) = {
None
}
}
private class VideoRenderer(ctx: VideoContext) extends Render[RenderVideo] {
override def renderJSON(json: String)(implicit jsCtx: PhantomJsContext) = {
None
}
}
}
trait Render[+Out] {
def renderJSON(json: String)(implicit jsCtx: PhantomJsContext): Option[Out]
}
Run Code Online (Sandbox Code Playgroud)
我为它的类型参数设置了渲染特征协变,所以如果
RenderImages <: BasicRender
Run Code Online (Sandbox Code Playgroud)
然后
ImagesRenderer <: Render[RenderImages]
Run Code Online (Sandbox Code Playgroud)
但看起来编译器无法在rendererFor中推断出渲染器的类型,所以我需要添加显式类转换
Some(new ImagesRenderer(ctx.asInstanceOf[ImagesContext]).asInstanceOf[Render[T]])
Run Code Online (Sandbox Code Playgroud)
我的理由在这里出了什么问题?
正如丹尼尔·C.索布拉尔解释,在这里你的问题是,你是动态的实例化不同的渲染器,在不类型系统捕捉之间的关系的方式ctx和结果类型rendererFor.解决此类问题的一种常见方法是使用类型类:
import java.io.File
class PhantomJsContext
trait Renderer[+Out] {
def renderJSON(json: String)(implicit jsCtx: PhantomJsContext): Option[Out]
}
trait RendererFactory[ContextType, ResultType] {
def buildRenderer( ctx: ContextType ): Renderer[ResultType]
}
object Renderer {
case class RenderImages(img: Array[File])
case class RenderVideo(video: File)
trait ImagesContext
trait VideoContext
def rendererFor[ContextType, ResultType](ctx: ContextType)( implicit factory: RendererFactory[ContextType, ResultType] ): Renderer[ResultType] = {
factory.buildRenderer( ctx )
}
class ImagesRenderer(ctx: ImagesContext) extends Renderer[RenderImages] {
def renderJSON(json: String)(implicit jsCtx: PhantomJsContext) = ???
}
implicit object ImagesRendererFactory extends RendererFactory[ImagesContext, RenderImages] {
def buildRenderer( ctx: ImagesContext ) = new ImagesRenderer( ctx )
}
class VideoRenderer(ctx: VideoContext) extends Renderer[RenderVideo] {
def renderJSON(json: String)(implicit jsCtx: PhantomJsContext) = ???
}
implicit object VideoRendererFactory extends RendererFactory[VideoContext, RenderVideo] {
def buildRenderer( ctx: VideoContext ) = new VideoRenderer( ctx )
}
}
Run Code Online (Sandbox Code Playgroud)
您可以轻松地在REPL中检查返回的正确类型:
scala> lazy val r1 = Renderer.rendererFor( new Renderer.ImagesContext {} )
r1: Renderer[Renderer.RenderImages] = <lazy>
scala> :type r1
Renderer[Renderer.RenderImages]
scala> lazy val r2 = Renderer.rendererFor( new Renderer.VideoContext {} )
r2: Renderer[Renderer.RenderVideo] = <lazy>
scala> :type r2
Renderer[Renderer.RenderVideo]
Run Code Online (Sandbox Code Playgroud)
T不推断:它是一个传递给方法的参数,并没有任何保证返回的是一个Option[Render[T]].例如,假设你传递RenderImages并返回a VideoRenderer,那么显然是错误的.
现在,if你放在那里的条件可能会阻止这种情况发生,但编译器没有使用它来确定你是否返回了正确的类型.
| 归档时间: |
|
| 查看次数: |
232 次 |
| 最近记录: |