21

私は、Scalaが型消去警告の影響を受けないようにするケースクラスで何をするのかを理解しようとしています。

次のような単純なクラス構造があるとします。それは基本的にEither

abstract class BlackOrWhite[A, B]

case class Black[A,B]( val left: A ) extends BlackOrWhite[A,B]

case class White[A,B]( val right: B ) extends BlackOrWhite[A,B]

そして、あなたはそれをこのように使おうとしています:

object Main extends App {

    def echo[A,B] ( input: BlackOrWhite[A,B] ) = input match {
        case Black(left) => println( "Black: " + left )
        case White(right) => println( "White: " + right )
    }

    echo( Black[String, Int]( "String!" ) )
    echo( White[String, Int]( 1234 ) )
}

すべてが問題なくコンパイルおよび実行されます。ただし、unapply自分でメソッドを実装しようとすると、コンパイラーは警告をスローします。Main上記と同じクラスで次のクラス構造を使用しました。

abstract class BlackOrWhite[A, B]

case class Black[A,B]( val left: A ) extends BlackOrWhite[A,B]

object White {

    def apply[A,B]( right: B ): White[A,B] = new White[A,B](right)

    def unapply[B]( value: White[_,B] ): Option[B] = Some( value.right )

}

class White[A,B]( val right: B ) extends BlackOrWhite[A,B]

フラグを使用してコンパイルすると-unchecked、次の警告が発行されます。

[info] Compiling 1 Scala source to target/scala-2.9.1.final/classes...
[warn] src/main/scala/Test.scala:41: non variable type-argument B in type pattern main.scala.White[_, B] is unchecked since it is eliminated by erasure
[warn]         case White(right) => println( "White: " + right )
[warn]                   ^
[warn] one warning found
[info] Running main.scala.Main

今、私は型消去を理解し、警告を回避しようとしましたManifests(これまでのところ役に立たない)が、2つの実装の違いは何ですか?ケースクラスは、追加する必要があることを実行していますか?これは回避できますManifestsか?

-Xprint:typerフラグをオンにした状態でscalaコンパイラーを介してcaseクラスの実装を実行しようとしましたが、unapplyメソッドは予想どおりに見えます。

case <synthetic> def unapply[A >: Nothing <: Any, B >: Nothing <: Any](x$0: $iw.$iw.White[A,B]): Option[B] = if (x$0.==(null))
    scala.this.None
else
    scala.Some.apply[B](x$0.right);
4

2 に答える 2

13

完全な回答はできませんが、コンパイラはケース クラスのunapplyメソッドを生成しますが、ケース クラスでパターン マッチする場合、その unapply メソッドは使用しないと言えます。-Ybrowse:typer組み込みのケース マッチングと独自のメソッドの両方を使用しようとすると、どちらを使用するかに応じてunapply( に対して) 非常に異なる構文ツリーが生成されることがわかります。match後のフェーズを参照して、違いが残っていることを確認することもできます。

Scala が組み込みの unapply を使用しない理由はわかりませんが、あなたが取り上げた理由かもしれません。そして、自分でそれを回避する方法はわかりunapplyません。しかしこれが、Scala が魔法のように問題を回避しているように見える理由です。

実験した後、明らかにこのバージョンのunapply作品ですが、その理由について少し混乱しています:

def unapply[A,B](value: BlackOrWhite[A,B]): Option[B] = value match {
    case w: White[_,_] => Some(w.right)
    case _ => None
}

あなたの難しさは、 a が a thenを拡張する場合、どうやらコンパイラがこのバージョンでは理解できるが、あなたのバージョンでは理解できunapplyないと確信する必要があることです。理由がわからない。White[A,B]BlackOrWhite[C,D]BD

于 2012-01-09T03:01:42.290 に答える
6

case class match と unapply の違いについてはお答えできません。ただし、彼らの本 (Odersky、Spoon、Venners) の「Programming in Scala」の 2 番目の chptr 26.6「Extractors vs case classes」には、次のように書かれています。

「Scala コンパイラーはエクストラクタよりもパターンをケース クラスよりもはるかに最適化できるため、それら (ケース クラス) は通常、エクストラクタよりも効率的なパターン マッチにつながります。これは、ケース クラスのメカニズムが固定されているためです。一方、unapply または unapplySeq メソッドは第 3 に、ケース クラスがシールされた基本クラスから継承する場合、Scala コンパイラはパターンの一致を網羅的にチェックし、可能な値の組み合わせがパターンでカバーされていない場合は文句を言います。エクストラクタのチェックを利用できます。」

つまり、この 2 つは一見しただけで予想されるよりもはるかに異なっていると言えますが、正確な違いが何であるかについて具体的に説明する必要はありません。

于 2012-01-09T13:17:08.053 に答える