捕获自由变量的 function object 被称为“闭合”在创建时可见的变量被称为 closure . 例如:
var foo = 10
val bar = (x:Int) => x+foo
这里, foo 在函数文字中是 free variable ,因此函数文字是 open term . 因此,val bar 是 closure ,因为函数值(对象)是使用开放项 foo 创建的 .
现在,让我们从函数定义的术语 val 和 def 开始 .
在scala中,function是一个值,您可以将其赋值给变量 .
使用 val 定义函数时,使用函数文字 val bar = (x:Int) => x+foo 定义它, return a function object 并将其作为值分配给 bar . 在 val 的情况下,函数值在定义时进行评估 . 这意味着,函数文字 (x:Int) => x+foo 被评估为具有自由变量 foo 的函数值,并作为 closure 存储在 bar 变量中 .
//In the following snippet, a function literal is evaluated to object Function1 and assigned to val bar.
scala> var foo = 10
foo: Int = 10
scala> val bar = (x: Int) => x + foo
bar: Int => Int = <function1> //Function1 object is returned
因为, bar 是一个值,并且在定义时进行求值,所以无论何时访问它都将始终引用内存中的同一对象 .
scala> bar eq bar //because both instance refer to same instance.
res11: Boolean = true
但是,根据规范,如果方法名称用作值,则Scala implicitly converts 将其与ETA Expression对应的函数类型 . 例如方法 def a: Int 转换为 a: => Int . 这意味着,每次调用方法时,它都是 returns a function value .
scala> def foo():Int = 1
a: ()Int
scala> val bar:( ()=> Int) = foo
bar: () => Int = <function0> //foo return Function0
//Note, val bar = foo, will assign the value returned by foo instead of returning function, so specify type.
因此, method can be used as function . 例如,当某些方法或函数需要函数类型作为参数时,您可以提供def方法 .
scala> val foo = (x:Int, double:Function1[Int, Int]) => double(x)
foo: (Int, Int => Int) => Int = <function2>
scala> def double(x:Int):Int = x * 2
double: (x: Int)Int
scala> foo(3, double)
res1: Int = 6
另外,请注意,使用方法,您可以在每次调用时获得新功能 .
scala> def double: Int => Int = _ * 2
double: Int => Int
scala> double eq double
res15: Boolean = false //false because every time double refers to new instance and hence is not equal unlike val.
Now, lets go to closure. 使用 val 和 def 方法定义的函数文字返回函数值(对象) . 从函数文字在运行时创建的函数值(对象)是闭包 . 另一方面,方法不是闭包,但是通过调用方法得到的函数值是闭包 .
scala> var more = 1
more: Int = 1
scala> val foo = (x:Int) => x + more // foo is clouser.
foo: Int => Int = <function1>
scala> def bar(x:Int):Int = x + more // bar is not clouser.
bar: (x: Int)Int
scala> val barClouser : (Int => Int) = bar // barClouser is clouser.
barClouser: Int => Int = <function1>
scala> val barValue = bar(3) // bar is converted to clouser and then clouser value is evaluated and result is assigned to barValue variable.
barValue: Int = 4
scala> val fooValue = foo(3) //foo value is evaluated and returned as value which is assigned to fooValue variable.
fooValue: Int = 4
2 回答
捕获自由变量的 function object 被称为“闭合”在创建时可见的变量被称为 closure . 例如:
这里,
foo
在函数文字中是 free variable ,因此函数文字是 open term . 因此,valbar
是 closure ,因为函数值(对象)是使用开放项foo
创建的 .现在,让我们从函数定义的术语 val 和 def 开始 .
使用 val 定义函数时,使用函数文字
val bar = (x:Int) => x+foo
定义它, return a function object 并将其作为值分配给bar
. 在 val 的情况下,函数值在定义时进行评估 . 这意味着,函数文字(x:Int) => x+foo
被评估为具有自由变量foo
的函数值,并作为 closure 存储在bar
变量中 .因为,
bar
是一个值,并且在定义时进行求值,所以无论何时访问它都将始终引用内存中的同一对象 .另一方面,您使用 def 和 method is not a function in Scala 定义 method . 根据Scala语言规范,method do not have type in Scala hence it cannot be used as value . 例如,你不能这样做:
但是,根据规范,如果方法名称用作值,则Scala implicitly converts 将其与ETA Expression对应的函数类型 . 例如方法
def a: Int
转换为a: => Int
. 这意味着,每次调用方法时,它都是 returns a function value .因此, method can be used as function . 例如,当某些方法或函数需要函数类型作为参数时,您可以提供def方法 .
另外,请注意,使用方法,您可以在每次调用时获得新功能 .
Now, lets go to closure. 使用 val 和 def 方法定义的函数文字返回函数值(对象) . 从函数文字在运行时创建的函数值(对象)是闭包 . 另一方面,方法不是闭包,但是通过调用方法得到的函数值是闭包 .
甚至互联网上有一些定义
closure
表明,如果函数捕获一个自由变量,那么它就是一个闭包,Martin Odersky对scala中闭包的定义由于
def
不是函数对象,因为它不是内存中的对象,我会说ep
即使是捕获自由变量也不是闭包 .函数文字和方法之间的差异:
声明函数文字时:
val phi= (x:Int)=>x+more
在运行时,您将创建一个
Function1[Int, Int]
类型的变量 . 它变为函数值,即变量占用内存(堆)中的空间 .声明函数声明时:
def ep(x:Int):Int= x+more
您在该类的虚拟方法表中创建一个新条目,而不占用堆中的空间,并且不需要GC来清理内容 .
另外
def
可以采用val
(函数值)不能的类型参数 .编辑
通过阅读Glossary关于函数值定义:
并且考虑到函数对象的上述定义,我们可以得出结论,定义为
def
的方法不是闭包,因为它不扩展任何FunctionN
特征,也不是用函数文字语法定义的 .创建def不会创建闭包,证明:
与...对比:
您可以看到创建def并没有吐出内存引用就像它使用函数文字语法一样 .