例如:
abstract class MyPoint case class OneDim(x : Int) extends MyPoint case class TwoDim(x : Int,y : Int) extends MyPoint var global_point : MyPoint = new OneDim(7) spawn { Thread.sleep(scala.util.Random.nextInt(100)) global_point = new TwoDim(3,9) } Thread.sleep(scala.util.Random.nextInt(100)) match global_point { case TwoDim(_,_) => println("Two Dim") case OneDim(_) => println("One Dim") }
是否有可能执行如下:
>主线程到达“match global_point”代码,发现* global_point *不是TwoDim类型并暂停(返回调度程序).
>生成的线程将* global_point *更改为TwoDim类型
>主线程返回,发现* global_point *不是OneDim类型,认为没有与* global_point *匹配并引发NoMatch异常.
Scala内部是否避免了这种执行?如果确实如此,那怎么样?匹配是否拍摄对象的快照,然后尝试将其与模式匹配?快照深度是否有限制(匹配模式可以是复杂的和嵌套的)?
解决方法
平面的例子
如果使用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以使其指向另一个对象,则匹配仍将发生在指向的旧对象上.因此,上面描述的情况(将global_point更改为指向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创建本地别名,并为它的两个子对象x.f(绑定到f)和x.x(绑定到ix),但不是为ix.f.因此,如果您匹配的结构是深度嵌套的,并且您的案例依赖于您未在本地绑定的嵌套对象,则可能会出现竞争条件.而且,正如我们都知道墨菲所知道的那样.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。