不可思议的1=2

这个问题最初是从https://issues.scala-lang.org/browse/SI-4939发现的

请看如下的代码片段:

scala> object Foo1 { val 1 = 2 }
    defined module Foo

scala> object Foo2 { val 1 = 1; def x = 1 }
defined module O

scala> Foo2.x
res1: Int = 1

scala> object Foo3 { val 1 = 2; def x = 1 }
defined module Foo3

scala> Foo3.x
scala.MatchError: 2
    at Foo3$.<init>(<console>:5)
    at Foo3$.<clinit>(<console>)
    at .<init>(<console>:7)
    at .<clinit>(<console>)
    at RequestResult$.<init>(<console>:9)

是不是觉得有点不可思议?且慢,我们把Foo3的定义放到一个Foo3.scala文件中,并用scalac带上参数-Xprint:typer进行编译后发现,val 1 =2被scala编译器解释为:

<synthetic> private[this] val x$1: Unit = (2: Int(2) @unchecked) match {
    case 1 => ()
}

还是无法理解?回忆一下模式匹配的用法:

scala> val (x,y)=(1,2)
x: Int = 1
y: Int = 2

scala> val (x,y,z)=(1,2,3)
x: Int = 1
y: Int = 2
z: Int = 3

是的, 在scala中等号=可以用来做模式匹配,val (x,y) = (1,2)事实上相当于 (1,2) match { case (x,y) => ()

明白了这个道理后,我们考虑一种特殊情况(没错,也许你已经想到),那就是val x = 2。平时我们会把这条语句理解为“将数值2赋值给变量x”。没错,大多数命令式编程语言都提供这样的赋值语句,但在函数式编程语言中,这又何尝不是一种模式匹配的实例呢?因此,我们最好还是把val x = 2理解为2 match { case x =>()}吧。如果你想通了,那么对val 1 =2就不再惊讶了。是的,val 1 =2相当于做了一次模式匹配运算,即2 match { case 1 => () } 。显而易见,执行这个模式匹配操作会抛出scala.MatchError错误。

现在我们回过头来分析Foo1,Foo2, Foo3的定义和执行结果。 Foo1就不用再解释了。Foo2和 Foo3都定义了一个函数x, 但是当调用Foo3.x的时候出现错误,而Foo2.x却一切正常。显然是由于val 1 =2 导致 Foo3.x 调用时出现错误,但是有人可能会问,Foo3.x 不就返回一个数值1嘛,跟scala.MatchError有什么关系? 别急,我们再调用Foo3.x看看:

scala> Foo3.x
java.lang.NoClassDefFoundError: Could not initialize class Foo3$
        at .<init>(<console>:9)
        at .<clinit>(<console>)
        at .<init>(<console>:11)
        at .<clinit>(<console>)
        at $export(<console>)

此时的错误变成java.lang.NoClassDefFoundError了,再调用一次Foo3.x,还是这个错。注意观察异常堆栈。看到了吗?对,初始化失败。 Foo3在初始化的时候会执行val 1 =2,根据刚才的分析,这里实际上是做了一次模式匹配运算,由于匹配失败,所以抛出scala.MatchError的异常,并终止了Foo3的初始化过程,从而导致Could not initialize class Foo3$

这就是函数式语言的魅力,简洁,抽象,一致。她彻底颠覆了传统命令式编程语言的"赋值"的概念,把“模式匹配”发挥到淋漓尽致。

转载于:https://my.oschina.net/aiguozhe/blog/33828

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值