【问题标题】:Understanding Case Class's 'unapply'了解案例类“不适用”
【发布时间】:2017-12-19 01:24:55
【问题描述】:

在下面的代码中,我试图了解Foo#unapply : Option[Int] 在模式匹配方面的用法。

$ls
Test.scala
$cat Test.scala 
object Test {

  case class Foo(x: Int)

  def f(foo: Foo): Unit = foo match {
    case Foo(_) => ()
  }

}

编译:

$scalac Test.scala 
$ls
Test$.class Test$Foo$.class Test$Foo.class  Test.class  Test.scala

我在每个 *class 文件上运行了 javap -c -v X.class | grep unapply。但是,我没有找到任何结果。

请解释Foo#unapply 是如何用于模式匹配的。另外,在哪里可以找到对应的JVM字节码指令?

【问题讨论】:

  • 您可以看到 scala 指令在执行 scalac -Xprint:typer Test.scala,您可以查看更多阶段以查看模式匹配如何扩展,例如在阶段 pickler
  • 您可以在f 的正文中找到Test$.class 中发生的事情。尽管您的用例很简单,但它非常简化。要查看更多信息,请尝试 case class Foo(x: Int, s: String) 并实际使用匹配值。

标签: scala


【解决方案1】:

如果您使用-Xprint:typer-print 进行编译,您将看到生成的代码。这是applyunapply的清理版,用scalac -Xprint:typer Test.scala编译:

case def apply(x: Int): com.yuval.Test.Foo = new Foo(x);
case def unapply(x$0: com.yuval.Test.Foo): Option[Int] = if (x$0.==(null))
    scala.this.None
  else
    Some.apply[Int](x$0.x);

f 保持不变:

def f(foo: com.yuval.Test.Foo): Unit = foo match {
  case (x: Int)com.yuval.Test.Foo(_) => ()
}

这是来自Test$.class的Java反编译代码:

public void f(Test.Foo foo) {
    Test.Foo localFoo = foo;
    if (localFoo != null) {
        BoxedUnit localBoxedUnit = BoxedUnit.UNIT;
    } else {
        throw new MatchError(localFoo);
    }
}

这是使用java -c -p Test$.class生成的字节码:

public void f(com.yuval.Test$Foo);
  Code:
   0: aload_1
   1: astore_2
   2: aload_2
   3: ifnull        11
   6: getstatic     #20    // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
   9: astore_3
  10: return
  11: new           #22    // class scala/MatchError
  14: dup
  15: aload_2
  16: invokespecial #25    // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
  19: athrow

这里的模式匹配变成了简单的类型检查。

【讨论】:

    猜你喜欢
    • 2019-05-11
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 2019-03-15
    • 1970-01-01
    • 2019-03-09
    • 2021-12-28
    • 1970-01-01
    相关资源
    最近更新 更多