これは仕様からの確固たる証拠ではありませんが、コンパイラーが行ういくつかのことを示しており、これにより、いくつかの一致ブロックをアトミックと見なすことができますが、すべてではないことは間違いありません。コードを自分で同期するか、不変オブジェクトを使用すると、より安全になります。
フラットの例
で次のスクリプトを実行するとscala -print
:
var m: Option[String] = _
m match {
case Some(s) => "Some: " + s
case None => "None"
}
コンパイラによって作成された desugared 中間コードが表示されます (簡潔にするために一部のコードを削除しました)。
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
。したがって、上記の状況( aではなくglobal_point
a を指すように変更する)は問題ではありません。TwoDim
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
一致するオブジェクトと、その 2 つのサブオブジェクトx.f
( にバインドf
) およびx.x
( にバインド) のローカル エイリアスを作成しますix
が、ix.f
. したがって、一致する構造が深くネストされていて、ローカルにバインドしていないネストされたオブジェクトにケースが依存している場合、競合状態が発生する可能性があります。そして、マーフィーの法則により、誰もが知っているようになります。