问题
In the following statement the val f
is defined as a lambda that references itself (it is recursive):
val f: Int => Int = (a: Int) =>
if (a > 10) 3 else f(a + 1) + 1 // just some simple function
I've tried it in the REPL, and it compiles and executes correctly.
According to the specification, this seems like an instance of illegal forward referencing:
In a statement sequence
s[1]...s[n]
making up a block, if a simple name ins[i]
refers to an entity defined bys[j]
wherej >= i
, then for alls[k]
between and includings[i]
ands[j]
,
s[k]
cannot be a variable definition.- If
s[k]
is a value definition, it must belazy
.
The assignment is a single statement, so it satisfied the j >= i
criteria, and it is included in the interval of statements the two rules apply to (between and including s[i]
and s[j]
).
However, it seems that it violates the second rule, because f
is not lazy.
How is that a legal statement (tried it in Scala 2.9.2)?
回答1:
You probably tried to use this in the REPL, which wraps all contents in an object definition. This is important because in Scala (or better: on the JVM) all instance values are initialized with a default value, which is null
for all AnyRefs
and 0
, 0.0
or false
for AnyVals
. For method values this default initialization does not happen, therefore you get an error message in this case:
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 }
^
This behavior can even lead to weird situations, therefore one should be careful with recursive instance values:
scala> val m: Int = m+1
m: Int = 1
scala> val s: String = s+" x"
s: String = null x
来源:https://stackoverflow.com/questions/24812376/why-is-it-possible-to-assign-recursive-lambdas-to-non-lazy-vals-in-scala