2017-01-26 2 views
1

これは、this questionのフォローアップです。ADTとタイプメンバーとのパターンマッチング

私は次のようにモデル化されたADTを持っている:

sealed trait Foo { 
    type A 
    def method: A 
} 

case class Bar(p: T, q: S) extends Foo { 
    type A = Array[String] 
    def method: A = // implementation 
} 

case class Baz(p: T, q: S) extends Foo { 
    type A = Map[Array[String], Array[String]] 
    def method: A = // implementation 
} 

私もそのコンストラクタのパラメータの1つとしてFooのサブタイプを取る別のクラスを持っている、そしてそれはBarBazのかどうかに基づいて特定の事柄を行います。

class Qux[X <: Foo](foo: X) { 
    val m: X#A = foo.method 

    def process = m match { 
    case a: Bar#A => // do stuff with Bar 
    case b: Baz#A => // do other stuff with Baz 
    } 

これがうまく働いたが、入力に起因する未チェックの種類についての警告につながった:そうは次のようにリンクされ、質問への受け入れ答えて

は、それがこのアイデアを実装するために、ユーザー@mariosによって私に示唆されました消去(Bazの場合はMapに一致しているので)。私の特別なケースでは、しかし、これらは安全に無視することができました。しかし、この場合には、私は私の質問は、なぜ、ある

[error] Qux.scala:4: type mismatch; 
[error] found : X#A 
[error] required: Array[String] 
[error] case Bar(_, _) => BarProcessor(m).doStuff(rows) 
[error]        ^

のようなエラーが出

class Qux[X <: Foo](foo: X) { 
    def process(param: U) = { 
    val m: X#A = foo.method 
    foo match { 
     case Bar(_, _) => BarProcessor(m).doStuff(param) // where BarProcessor expects m to be an Array[String] 
     case Baz(_, _) => BazProcessor(m.keys).doStuff(param, m.values) // do related stuff using m, but where m is instead now a Map[Array[String], Array[String]] 
    } 
    } 
} 

:?しかし、私はこれを避けることができればと思った、とこのような何かを書き込もうとしましたかこれらの2つのコードスニペットは実際にはまったく異なるようには見えません。なぜ、型メンバーにアクセスするのが最初のケースでは動作しますが、2番目では動作しませんか?

答えて

2

コンパイラも分岐に応じfooの種類を絞り込むない、mのはるかに少ない(すなわちブランチの内側、fooの種類はまだXなく、Bar又はBazです)。あなたが代わりに書くことができることは、パターン内fooが実際に外fooをシャドウ新鮮な変数であるので、これは

foo match { 
     case bar: Bar => 
     val m = bar.method // m is Bar#A, i.e. Array[String] 
     // note that if you use foo here, it still has type Foo 
     BarProcessor(m).doStuff(param) 
     ... 
と同等であることを

def process(param: U) = { 
    foo match { 
     case foo: Bar => 
     val m = foo.method // m is Bar#A, i.e. Array[String] 
     BarProcessor(m).doStuff(param) 
     case foo: Baz => 
     val m = foo.method // m is Baz#A, i.e. Map[Array[String], Array[String]] 
     BazProcessor(m.keys).doStuff(param, m.values) 
    } 
    } 

注意です

関連する問題