我基本上是函数式编程和 scala 的新手,下面的问题可能看起来很愚蠢。
val f = (a:Int) => a+1
在上面的代码片段中,我应该将其视为f
函数还是变量?来自 C/C++ 背景,第一个想法是它f
是一个存储匿名函数返回值的变量,但我认为这不是解释它的正确方法任何解释都会非常有帮助。
(我上面使用的一些术语在 scala/函数式编程方面可能是错误的,请多多包涵)
我基本上是函数式编程和 scala 的新手,下面的问题可能看起来很愚蠢。
val f = (a:Int) => a+1
在上面的代码片段中,我应该将其视为f
函数还是变量?来自 C/C++ 背景,第一个想法是它f
是一个存储匿名函数返回值的变量,但我认为这不是解释它的正确方法任何解释都会非常有帮助。
(我上面使用的一些术语在 scala/函数式编程方面可能是错误的,请多多包涵)
这里,f
是一个存储函数的变量。这实际上与说以下任何内容没有什么不同:
val a = 4 // `a` is a variable storing an Int
val b = "hi" // `b` is a variable storing a String
val f = (a:Int) => a+1 // `f` is a variable storing a function
您也可以通过 REPL 确认这一点:
scala> val f = (a:Int) => a+1
f: Int => Int = <function1>
所以这告诉你f
有 type Int => Int
。或者换句话说,f
是一个接受一个参数 anInt
并返回 an的函数Int
。
由于f
是一个变量,因此您可以在其上调用方法或将其作为参数传递给期望其类型的函数:
a + 3 // here I'm calling the `+` method on `a`, which is an Int
f(3) // here I'm calling the `apply` method on `f`, which is a function `Int => Int`
f(a) // the function `f` expects an `Int`, which `a` is
(1 to 3).map(f) // the `map` method expects a function from Int to Int, like `f`
是的,就像 dhg 所说,f
是一个存储函数的变量(不能更改)。
然而,这里有一个微妙之处:
...出现的第一个想法是f是一个存储匿名函数返回值的变量
f
实际上存储的是函数,而不是结果。所以你可以给它不同的输入,得到不同的输出。所以,你可以像f(7)
then一样使用它f(5)
。Scala 中的函数是对象,因此可以分配给变量、作为参数传递等。
我最近发布了有关 function literals的帖子,这可能对您有所帮助。
f
是一个表示函数字面量的值。
在语句中,右边是一个函数字面量。左侧将其绑定到一个名称,然后称为value(val
关键字类似于let
LISP 中的关键字)。现在函数与符号相关联f
,因此您可以使用此符号引用该函数f
。
我不同意其他建议将f
其称为变量的答案。是一个值,因为它被固定为仅确定一次且不能更改f
的右侧项。相反,用 引入的变量允许您将值重新分配给符号:var
var f = (i: Int) => i + 1
变量定义在哪里var
开始,f
是变量的名称或符号,可能有一个可选: ...
的变量定义类型(如果你不考虑,类型会自动从赋值中推断出来),并= ...
定义最初分配给多变的。
因此,当人们说value时,不要将其与数字常量混淆,它只是一个不变的实体。一个函数也可以是一个值,因为f
then 总是表示同一个相同的函数,即使你可以为该函数提供不同的参数,从而产生不同的结果。
现在,var
您可以重新分配其右侧:
f(2) // --> 3
f = (i: Int) => i * 2 // assign a new function to the variable f.
f(2) // --> 4
函数式编程就是要避免变量(重新分配)。
也可以定义一个函数而不分配它(给一个值或变量)。下面定义了这样一个函数并立即使用参数调用它4
:
{ i: Int => i + 1 } apply 4 // --> 5
尽管作为语句本身很少有用,但是在调用需要函数参数的方法时,您会经常看到“普通”函数。例如
val s = List(1, 2, 3)
s.map { (i: Int) => i + 1 } // --> List(2, 3, 4)
s.map { _ + 1 } // equivalent
s.map( _ + 1 ) // equivalent