在Scala中定义函数的这三种方法之间的差异
给出了表示相同函数的三种方法在Scala中定义函数的这三种方法之间的差异,scala,Scala,给出了表示相同函数的三种方法f(a):=a+1: val f1 = (a:Int) => a + 1 def f2 = (a:Int) => a + 1 def f3:(Int => Int) = a => a + 1 这些定义有何不同?REPL未显示任何明显差异: scala> f1 res38: (Int) => Int = <function1> scala> f2 res39: (Int) => Int = <funct
f(a):=a+1
:
val f1 = (a:Int) => a + 1
def f2 = (a:Int) => a + 1
def f3:(Int => Int) = a => a + 1
这些定义有何不同?REPL未显示任何明显差异:
scala> f1
res38: (Int) => Int = <function1>
scala> f2
res39: (Int) => Int = <function1>
scala> f3
res40: (Int) => Int = <function1>
scala>f1
res38:(Int)=>Int=
scala>f2
res39:(Int)=>Int=
scala>f3
res40:(Int)=>Int=
f1
是一个接受整数并返回整数的函数
f2
是一种具有零arity的方法,它返回一个接受整数并返回整数的函数。(稍后在REPL中键入f2
时,它将成为对方法f2
的调用)
f3
与f2
相同。在类中,val
在初始化时进行计算,而def
仅在每次调用函数时进行计算。在下面的代码中,您将看到在第一次使用对象时计算x,但在访问x成员时不会再次计算x。相反,在实例化对象时不计算y,而是在每次访问成员时计算y
class A(a: Int) {
val x = { println("x is set to something"); a }
def y = { println("y is set to something"); a }
}
// Prints: x is set to something
val a = new A(1)
// Prints: "1"
println(a.x)
// Prints: "1"
println(a.x)
// Prints: "y is set to something" and "1"
println(a.y)
// Prints: "y is set to something" and "1"
println(a.y)
执行定义(如defx=e)将不会计算表达式e。相反,每当使用x时,都会计算e。或者,Scala提供了一个值定义 valx=e,作为评估的一部分,它会评估右侧e 定义的定义。如果随后使用x,则立即用 预先计算的值e,因此表达式无需再次求值 Scala示例 作者:马丁·奥德斯基
您应该注意,在上面的第2个块中,在REPL中计算
f1
显示静态绑定到f1
的值,同时计算f2
和f3
显示调用这些方法的结果。特别是,每次调用f2
或f3
时都会生成一个新的Function1[Int,Int]
实例,而f1
永远是相同的Function1[Int,Int]
。@RandallSchulz,因为val版本不需要新的函数实例,为什么会在这种情况下使用def?@virtualeyes我能回忆起的唯一一种情况是,在combinator解析器库中,可以看到def生成函数n[…]值。编写生成函数的方法并不常见,而且几乎不会使用def生成语义/功能不变函数的多个副本。为什么f1
是函数
,f2
是方法
?@Freewind,函数是名为apply
的对象。一种方法,好吧,就是一种方法。真棒的答案。问:你说f2的算术为零,但它不是一元数吗?“空函数不带参数。一元函数带一个参数。”真奇怪@马修康奈尔,f2
本身不接受任何参数。它返回的函数对象确实如此。@JacobusR只有在类中才是真的吗?例如:scala>varb=5b:Int=5scala>vala:(Int=>Int)=x=>x+baa:Int=>Int=scala>a(5)res48:Int=10scala>b=6b:Int=6scala>a(5)res49:Int=11我期待的是a(5)返回10,b的值已被修改inlined@AndrewCassidy函数a
是不可变的,并在初始化时进行评估,但b
仍然是可变值。因此,对b
的引用在初始化过程中设置,但b
存储的值保持可变。为了好玩,您现在可以创建一个新的val b=123
。在此之后,a(5)
将始终给出11,因为b
现在是一个全新的值。@JacobusR谢谢。。。这是有道理的。这与“词法范围”的定义一致,因为函数a引用了原始的“var b”。我想让我困惑的是:VarB=5;val c=b;b=6;行为不同。我想我不应该期望一个包含对原始“词法”范围的引用的函数定义与Int的行为方式相同。