这不是规范中的确凿证据,但它说明了编译器为您所做的一些事情,这应该允许您将一些匹配块视为原子 -但绝对不是全部。如果您自己同步代码,或者使用不可变对象,这会更安全。
平面示例
如果您使用以下脚本运行scala -print
:
var m: Option[String] = _
m match {
case Some(s) => "Some: " + s
case None => "None"
}
您将看到编译器创建的脱糖中间代码(为简洁起见,我删除了一些代码):
final class Main$$anon$1 extends java.lang.Object {
private[this] var m: Option = _;
private <accessor> def m(): Option = Main$$anon$1.this.m;
def this(): anonymous class Main$$anon$1 = {
<synthetic> val temp1: Option = Main$$anon$1.this.m();
if (temp1.$isInstanceOf[Some]()) {
"Some: ".+(temp1.$asInstanceOf[Some]().x())
else if (scala.this.None.==(temp1))
"None"
else
throw new MatchError(temp1)
}
}
引用的可能共享对象m
获得一个本地别名temp1
,因此如果m
在后台更改以使其指向另一个对象,则匹配仍然发生在所m
指向的旧对象上。因此,您上面描述的情况(更改global_point
为指向 aTwoDim
而不是指向 a OneDim
)不是问题。
嵌套示例
通常情况下,编译器似乎会为绑定在匹配案例保护中的所有对象创建本地别名,但它不会创建深层副本!对于以下脚本:
case class X(var f: Int, var x: X)
var x = new X(-1, new X(1, null))
x match {
case X(f, ix) if f > 0 || ix.f > 0 => "gt0"
case X(f, ix) if f <= 0 || ix.f <= 0 => "lte0"
}
编译器创建这个中间代码:
private[this] var x: anonymous class Main$$anon$1$X = _;
private <accessor> def x(): anonymous class Main$$anon$1$X = Main$$anon$1.this.x;
final <synthetic> private[this] def gd2$1(x$1: Int, x$2: anonymous class Main$$anon$1$X): Boolean = x$1.>(0).||(x$2.f().>(0));
final <synthetic> private[this] def gd3$1(x$1: Int, x$2: anonymous class Main$$anon$1$X): Boolean = x$1.<=(0).||(x$2.f().<=(0));
def this(): anonymous class Main$$anon$1 = {
<synthetic> val temp6: anonymous class Main$$anon$1$X = Main$$anon$1.this.x();
if (temp6.ne(null)) {
<synthetic> val temp7: Int = temp6.f();
<synthetic> val temp8: anonymous class Main$$anon$1$X = temp6.x();
if (Main$$anon$1.this.gd2$1(temp7, temp8))
"gt0"
else if (Main$$anon$1.this.gd3$1(temp7, temp8))
"lte0"
else
throw new MatchError(temp6)
} else
throw new MatchError(temp6)
}
x
在这里,编译器为您匹配的对象及其两个子对象x.f
(绑定到f
)和x.x
(绑定到)创建本地别名ix
,但不为ix.f
. 因此,如果您匹配的结构是深度嵌套的,并且您的案例依赖于您未在本地绑定的嵌套对象,则可能会发生竞争条件。众所周知,由于墨菲定律,并且会。