Путаница в сопоставлении паттерна Scala с Option [Any] - PullRequest
31 голосов
/ 24 сентября 2010

У меня есть следующий код 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)

Какое объяснение?

В качестве второго вопроса я получаю 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

Ответы [ 3 ]

44 голосов
/ 24 сентября 2010

Это из-за стирания типа.JVM не знает ни одного параметра типа, кроме как с массивами.Из-за этого, код Scala не может проверить, является ли Option Option[Int] или Option[String] - эта информация была стерта.1006 *

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 перейдет к регистру по умолчанию.

8 голосов
/ 24 сентября 2010

Любая информация о параметрах типа доступна только во время компиляции, а не во время выполнения (это называется стиранием типа).Это означает, что во время выполнения нет никакой разницы между Option[String] и Option[Int], поэтому любой шаблон, соответствующий типу Option[String], также будет соответствовать Option[Int], потому что во время выполнения оба равны Option.

* 1007.* Поскольку это почти всегда не то, что вы намереваетесь, вы получите предупреждение.Единственный способ избежать предупреждения - не проверять универсальный тип чего-либо во время выполнения (это нормально, потому что это не работает так, как вы этого хотите).

Нет способа проверить, является лиOption - это Option[Int] или Option[String] во время выполнения (кроме проверки содержимого, если это Some).

2 голосов
/ 24 сентября 2010

Как уже говорилось, вы здесь против стирания.

Для решения ... С актором 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 _ =>
    }
  }
}
...