为什么在Scala中可以将递归lambda分配给非懒惰val



在以下语句中,val f被定义为引用自身的lambda(它是递归的(:

val f: Int => Int = (a: Int) =>
    if (a > 10) 3 else f(a + 1) + 1 // just some simple function

我在REPL中尝试过,它编译和执行都是正确的。

根据规范,这似乎是非法前向引用的一个例子:

在组成一个块的语句序列s[1]...s[n]中,如果3中的名称是指由CCD_ 4定义的实体,则对于在s[i]s[j]之间(包括CCD_7(的所有s[k]

  • s[k]不能是变量定义
  • 如果s[k]是一个值定义,则它必须是lazy

赋值是一个单独的语句,因此它满足j >= i标准,并且它包含在两个规则适用的语句间隔中(介于s[i]s[j]之间,包括CCD_14(。

然而,它似乎违反了第二条规则,因为f并不懒惰。

这怎么是一个法律声明(在Scala2.9.2中尝试过(?

您可能试图在REPL中使用它,REPL将所有内容封装在对象定义中。这一点很重要,因为在Scala中(或者更好:在JVM上(,所有实例值都是用默认值初始化的,对于所有AnyRefs,默认值是null;对于AnyVals,默认值为00.0false。对于方法值,此默认初始化不会发生,因此在这种情况下会收到一条错误消息:

scala> object x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
defined object x
scala> def x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
<console>:7: error: forward reference extends over definition of value f
       def x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
                                                           ^

这种行为甚至会导致奇怪的情况,因此应该小心递归实例值:

scala> val m: Int = m+1
m: Int = 1
scala> val s: String = s+" x"
s: String = null x

最新更新