2

後でパターン マッチングを行う次のデータ モデルがあります。

abstract class A
case class C(s:String) extends A

abstract class B extends A
case class D(i:Int) extends B
case class E(s:Int, e:Int) extends B

A は、階層の抽象スーパー タイプです。C は A の具象サブクラスです。A の他の具象サブクラスは B のサブクラスであり、B は A のサブクラスです。

今、私がこのようなものを書くと、うまくいきます:

def match(a:A) a match {
   a:C => println("C")
   a:B => println("B")
}

ただし、for ループでは B と一致させることはできません。コンストラクター パターンが必要だと思いますが、B は抽象的であるため、B のコンストラクター パターンはありません。

val list:List[A] = List(C("a"), D(1), E(2,5), ...)

for (b:B <- list) println(b)  // Compile error
for (b@B <- list) println(b)  // Compile error

ここでは、B インスタンスのみを出力したいと思います。この場合の回避策はありますか?

4

4 に答える 4

3

使用できますcollect

list.collect { case b: B => println(b) }

これをよりよく理解したい場合は、部分関数について読むことをお勧めします。ここで例を挙げます。

于 2013-01-25T11:15:10.453 に答える
2

セルゲイは正しいです。パターン マッチとインスタンスforのみのフィルタリングが必要な場合は、あきらめる必要があります。なんらかの理由で内包表記を使用したいB場合は、ガードを使用するのが1 つの方法だと思います。for

for (b <- list if b.isInstanceOf[B]) println(b)

ただし、 の代わりにパターン マッチングを選択することをお勧めしisInstanceOfます。したがって、私はcollect提案を受け入れます (残りのコードのコンテキストで意味がある場合)。

もう 1 つの提案は、コンパニオン オブジェクトB同じ名前で定義し、unapplyメソッドを定義することです。

abstract class A
case class C(s:String) extends A

abstract class B extends A
object B { def unapply(b: B) = Option(b)  } // Added a companion to B
case class D(i:Int) extends B
case class E(s:Int, e:Int) extends B

次に、これを行うことができます:

for (B(b) <- list) println(b)

つまり、これは B の「コンストラクタ」ではなく、コンパニオンのunapplyメソッドです。それは機能します、そしてそれが友達の目的ですよね?

( http://www.scala-lang.org/node/112を参照)

于 2013-01-25T11:35:49.620 に答える
2

私に言わせれば、ここでパターンマッチングが使えないのは残念ながらscalaの矛盾です。実際、次の例が示すように、scalaでは内包表記のパターン マッチが可能です。

val list:List[A] = List(C("a"), D(1), E(2,5)
for ((b:B,_) <- list.map(_ -> null)) println(b)

ここでは、要素を一時的にペア (ダミーで未使用の 2 番目の値) にラップし、最初の要素が型 B であるペアのパターン マッチを行います。出力が示すように、期待される動作が得られます。

 D(1)
 E(2,5)

というわけで、scalaパターン マッチングに基づくフィルタリングをサポートしています (タイプによるマッチングの場合でも)。文法は、単一要素のタイプによるパターン マッチングを処理しないようです。

明らかに、私はこのトリックを使用することを勧めているわけではありません。これは説明のためのものです。使っcollectたほうが断然いいです。

繰り返しになりますが、何らかの理由で内包表記が本当に好きな場合は、別のより一般的な解決策があります。

object Value {
  def unapply[T]( value: T ) = Some( value )
}
for ( Value(b:B) <- list ) println(b)

Valueオブジェクトにダミーのエクストラクターを導入しましたが、これは何もしないため、前者がコンパイルされることを除いて、Value(b:B)just と同じ意味になります。b:Bそして、ペアを使った以前のトリックとは異なり、比較的読みやすく、Value1 回書くだけでよく、その後は自由に使用できます (特に、パターン マッチの対象となる型ごとに新しいエクストラクタを記述する必要はありません。 @Faiz's answer. 私はあなたにもっと良い名前を見つけさせますValue

最後に、すぐに使える別の回避策があります (クレジットは Daniel Sobral に送られます) が、やや読みにくく、ダミーの識別子が必要です (こちらfoo)。

for ( b @(foo:B) <- list ) println(b)
// or similarly:
for ( foo @(b:B) <- list ) println(b)
于 2013-01-25T13:08:02.633 に答える
0

私の2セント:理解度チェックタイプに条件を追加できますが、クラスBのインスタンスのみを取る使用ほどエレガントではありません.collect

于 2013-01-25T11:39:59.920 に答える