次のScalaコードがあります。
import scala.actors.Actor
object Alice extends Actor {
this.start
def act{
loop{
react {
case "Hello" => sender ! "Hi"
case i:Int => sender ! 0
}
}
}
}
object Test {
def test = {
(Alice !? (100, "Hello")) match {
case i:Some[Int] => println ("Int received "+i)
case s:Some[String] => println ("String received "+s)
case _ =>
}
(Alice !? (100, 1)) match {
case i:Some[Int] => println ("Int received "+i)
case s:Some[String] => println ("String received "+s)
case _ =>
}
}
}
Test.test
を実行すると、次のような出力が得られます。
scala> Test.test
Int received Some(Hi)
Int received Some(0)
出力を期待していた
String received Some(Hi)
Int received Some(0)
説明は何ですか?
2番目の質問として、上記のunchecked
警告が次のように表示されます。
C:\scalac -unchecked a.scala
a.scala:17: warning: non variable type-argument Int in type pattern Some[Int] is unchecked since it is eliminated by erasure
case i:Some[Int] => println ("Int received "+i)
^
a.scala:18: warning: non variable type-argument String in type pattern Some[String] is unchecked since it is eliminated by erasure
case s:Some[String] => println ("String received "+s)
^
a.scala:22: warning: non variable type-argument Int in type pattern Some[Int] is unchecked since it is eliminated by erasure
case i:Some[Int] => println ("Int received "+i)
^
a.scala:23: warning: non variable type-argument String in type pattern Some[String] is unchecked since it is eliminated by erasure
case s:Some[String] => println ("String received "+s)
^
four warnings found
警告を回避するにはどうすればよいですか?
編集:提案をありがとう。ダニエルのアイデアは素晴らしいですが、以下の例のように、ジェネリック型では機能しないようです
def test[T] = (Alice !? (100, "Hello")) match {
case Some(i: Int) => println ("Int received "+i)
case Some(t: T) => println ("T received ")
case _ =>
}
以下 エラー 警告が発生しました:warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure
これは型消去によるものです。 JVMは、配列を除いて、型パラメーターを認識しません。そのため、Scalaコードは、Option
がOption[Int]
であるかOption[String]
であるかを確認できません-その情報は消去されています。
ただし、次の方法でコードを修正できます。
object Test {
def test = {
(Alice !? (100, "Hello")) match {
case Some(i: Int) => println ("Int received "+i)
case Some(s: String) => println ("String received "+s)
case _ =>
}
(Alice !? (100, 1)) match {
case Some(i: Int) => println ("Int received "+i)
case Some(s: String) => println ("String received "+s)
case _ =>
}
}
}
この方法では、Option
のタイプをテストするのではなく、そのコンテンツのタイプをテストします-コンテンツがあると仮定します。 None
はデフォルトのケースになります。
型パラメーターに関する情報は、実行時ではなくコンパイル時にのみ利用できます(これは型消去と呼ばれます)。これは、実行時にOption[String]
とOption[Int]
の間に違いがないことを意味します。したがって、タイプOption[String]
でのパターンマッチングもOption[Int]
と一致します。これは、ランタイムでは両方ともOption
。
これはほとんどの場合意図したものではないため、警告が表示されます。警告を回避する唯一の方法は、実行時に何かのジェネリック型をチェックしないことです(とにかく期待どおりに機能しないため、問題ありません)。
実行時に、Option
がOption[Int]
であるかOption[String]
であるかを確認する方法はありません(コンテンツがSome
であるかどうかを調べる以外に)。
すでに述べたように、あなたはここで消去に反対しています。
Scalaアクターでは、送信する可能性のある各メッセージタイプのケースクラスを定義するのが普通です。
case class MessageTypeA(s : String)
case class MessageTypeB(i : Int)
object Alice extends Actor {
this.start
def act{
loop{
react {
case "Hello" => sender ! MessageTypeA("Hi")
case i:Int => sender ! MessageTypeB(0)
}
}
}
}
object Test {
def test = {
(Alice !? (100, "Hello")) match {
case Some(MessageTypeB(i)) => println ("Int received "+i)
case Some(MessageTypeA(s)) => println ("String received "+s)
case _ =>
}
(Alice !? (100, 1)) match {
case Some(MessageTypeB(i)) => println ("Int received " + i)
case Some(MessageTypeA(s)) => println ("String received " + s)
case _ =>
}
}
}