2016-06-20 3 views
1

私が達成しようとしていることを示すために、以下のような工夫した例を作成しました。私はそれが処理する特定のタイプのリクエストでパラメータ化されたクラスを吐き出すファクトリを探しています。私はジェネリックスを理解していると思ったが、今は自分自身を疑う。 :)でScala:ネストされたジェネリックスでタイプの不一致があります

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

結果:助けを事前に

Compiler exception error: line 32: type mismatch; found : Evaluator__da15fb805d29b29227bc28ccae6cd07d2c04cb40_1274353927.Test.ctx.type (with underlying type RequestContext) required: _$2 source.get(ctx)

ありがとう!

答えて

1

スカラーは、SourceFactory.applyまたはRequestContextFactory.applyのいずれかに、Tを絶対に推論する方法がありません。これは、引数には現れないためです。あなたはSourceFactory[Nothing]RequestContextFactory[RequestContext]を呼び出しています(2番目は、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はパス依存型と呼ばれるこの形式をサポートしていますが、ここでは適用できません。あなただけexistentialsを型パラメータを削除し、使用することを試みることができる:

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()) 
    } 
} 
+0

、どうもありがとう! – richid

関連する問題