Scala 模式匹配与 Option[Any] 的混淆

发布于 2024-09-25 03:19:10 字数 2180 浏览 7 评论 0原文

我有以下 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

如何避免警告?

编辑:感谢您的建议。 Daniel 的想法不错,但似乎不适用于泛型类型,如下例所示

def test[T] = (Alice !? (100, "Hello")) match { 
   case Some(i: Int) => println ("Int received "+i) 
   case Some(t: T) => println ("T received ") 
   case _ =>  
}

遇到以下 error 警告: warning: 类型模式 T 中的抽象类型 T 未选中,因为它是通过擦除消除

I have the following Scala code.

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 _ =>
    }
  }
}

After doing Test.test, I get the output:

scala> Test.test
Int received Some(Hi)
Int received Some(0)

I was expecting the output

String received Some(Hi)
Int received Some(0)

What is the explanation?

As a second question, I get unchecked warnings with the above as follows:

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

How can I avoid the warnings?

EDIT: Thanks for the suggestions. Daniel's idea is nice but does not seem to work with generic types, as in the example below

def test[T] = (Alice !? (100, "Hello")) match { 
   case Some(i: Int) => println ("Int received "+i) 
   case Some(t: T) => println ("T received ") 
   case _ =>  
}

The following error warning is encountered: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

对风讲故事 2024-10-02 03:19:10

这是由于类型擦除造成的。 JVM 不知道除数组之外的任何类型参数。因此,Scala 代码无法检查 OptionOption[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 将属于默认情况。

This is due to type-erasure. The JVM does not know of any type parameter, except on arrays. Because of that, Scala code can't check whether an Option is an Option[Int] or an Option[String] -- that information has been erased.

You could fix your code this way, though:

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 _ =>
    }
  }
}

This way you are not testing what the type of Option is, but what the type of its contents are -- assuming there is any content. A None will fall through to the default case.

最舍不得你 2024-10-02 03:19:10

有关类型参数的任何信息仅在编译时可用,而不是在运行时可用(这称为类型擦除)。这意味着在运行时,Option[String]Option[Int] 之间没有区别,因此类型 Option[String] 上的任何模式都匹配code> 也将匹配 Option[Int],因为在运行时两者都只是 Option

由于这几乎总是不是您想要的,因此您会收到警告。避免警告的唯一方法是不要在运行时检查某些内容的通用类型(这很好,因为无论如何它都不会像您希望的那样工作)。

无法在运行时检查 OptionOption[Int] 还是 Option[String](除了检查内容)如果是Some)。

Any information about type parameters is only available at compile-time, not at runtime (this is known as type erasure). This means that at runtime there is no difference between Option[String] and Option[Int], so any pattern matching on the type Option[String], will also match Option[Int] because at runtime both is just Option.

Since this is almost always not what you intend, you get a warning. The only way to avoid the warning is not to check the generic type of something at runtime (which is fine because that doesn't work like you want it to anyway).

There is no way to check whether an Option is an Option[Int] or an Option[String] at runtime (other than inspecting the content if it's a Some).

萌酱 2024-10-02 03:19:10

正如已经说过的,你在这里面临着删除。

对于解决方案...Scala actor 为您可能发送的每种消息类型定义案例类是正常的:

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 _ =>
    }
  }
}

As already stated, you're up against erasure here.

For the solution... It's normal with Scala actor to define case classes for each message type you're likely to send:

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 _ =>
    }
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文