scala 定义函数的“def”和“val”有什么区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18887264/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between "def" and "val" to define a function
提问by Amir Karimi
What is the difference between:
有什么区别:
def even: Int => Boolean = _ % 2 == 0
and
和
val even: Int => Boolean = _ % 2 == 0
Both can be called like even(10).
两者都可以称为 like even(10)。
回答by senia
Method def evenevaluates on call and creates new function every time (new instance of Function1).
方法def even在调用时评估并每次创建新函数( 的新实例Function1)。
def even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = false
val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true
With defyou can get new function on every call:
有了def你可以在每次调用新的功能:
val test: () => Int = {
val r = util.Random.nextInt
() => r
}
test()
// Int = -1049057402
test()
// Int = -1049057402 - same result
def test: () => Int = {
val r = util.Random.nextInt
() => r
}
test()
// Int = -240885810
test()
// Int = -1002157461 - new result
valevaluates when defined, def- when called:
val定义def时评估,- 调用时:
scala> val even: Int => Boolean = ???
scala.NotImplementedError: an implementation is missing
scala> def even: Int => Boolean = ???
even: Int => Boolean
scala> even
scala.NotImplementedError: an implementation is missing
Note that there is a third option: lazy val.
请注意,还有第三种选择:lazy val.
It evaluates when called the first time:
它在第一次调用时进行评估:
scala> lazy val even: Int => Boolean = ???
even: Int => Boolean = <lazy>
scala> even
scala.NotImplementedError: an implementation is missing
But returns the same result (in this case same instance of FunctionN) every time:
但FunctionN每次都返回相同的结果(在本例中为 的相同实例):
lazy val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true
lazy val test: () => Int = {
val r = util.Random.nextInt
() => r
}
test()
// Int = -1068569869
test()
// Int = -1068569869 - same result
Performance
表现
valevaluates when defined.
val定义时进行评估。
defevaluates on every call, so performance could be worse than valfor multiple calls. You'll get the same performance with a single call. And with no calls you'll get no overhead from def, so you can define it even if you will not use it in some branches.
def对每次调用进行评估,因此性能可能比val多次调用更差。一次调用即可获得相同的性能。并且没有调用,您将不会从 中获得任何开销def,因此即使您不会在某些分支中使用它,您也可以定义它。
With a lazy valyou'll get a lazy evaluation: you can define it even if you will not use it in some branches, and it evaluates once or never, but you'll get a little overhead from double check locking on every access to your lazy val.
使用 alazy val你会得到一个懒惰的评估:即使你不会在某些分支中使用它,你也可以定义它,它评估一次或从不评估,但是你会从每次访问你的lazy val.
As @SargeBorsch noted you could define method, and this is the fastest option:
正如@SargeBorsch 指出的,您可以定义方法,这是最快的选择:
def even(i: Int): Boolean = i % 2 == 0
But if you need a function (not method) for function composition or for higher order functions (like filter(even)) compiler will generate a function from your method every time you are using it as function, so performance could be slightly worse than with val.
但是,如果您需要一个函数(不是方法)用于函数组合或高阶函数(如filter(even)),编译器将在您每次将其用作函数时从您的方法生成一个函数,因此性能可能比使用val.
回答by Jatin
Consider this:
考虑一下:
scala> def even: (Int => Boolean) = {
println("def");
(x => x % 2 == 0)
}
even: Int => Boolean
scala> val even2: (Int => Boolean) = {
println("val");
(x => x % 2 == 0)
}
val //gets printed while declaration. line-4
even2: Int => Boolean = <function1>
scala> even(1)
def
res9: Boolean = false
scala> even2(1)
res10: Boolean = false
Do you see the difference? In short:
你看得到差别吗?简而言之:
def: For every call to even, it calls the body of the evenmethod again. But with even2i.e. val, the function is initialized only once while declaration (and hence it prints valat line 4 and never again) and the same output is used each time it accessed. For example try doing this:
def:对于每次调用even,它都会even再次调用方法的主体。但是对于even2ie val,该函数在声明时仅初始化一次(因此它val在第 4 行打印并且不再打印)并且每次访问时都使用相同的输出。例如尝试这样做:
scala> import scala.util.Random
import scala.util.Random
scala> val x = { Random.nextInt }
x: Int = -1307706866
scala> x
res0: Int = -1307706866
scala> x
res1: Int = -1307706866
When xis initialized, the value returned by Random.nextIntis set as the final value of x. Next time xis used again, it will always return the same value.
当x被初始化,则返回值被Random.nextInt设置为最终值x。下次x再次使用时,将始终返回相同的值。
You can also lazily initialize x. i.e. first time it is used it is initialized and not while declaration. For example:
您也可以延迟初始化x。即第一次使用它被初始化而不是在声明时。例如:
scala> lazy val y = { Random.nextInt }
y: Int = <lazy>
scala> y
res4: Int = 323930673
scala> y
res5: Int = 323930673
回答by Apurva Singh
See this:
看到这个:
var x = 2 // using var as I need to change it to 3 later
val sq = x*x // evaluates right now
x = 3 // no effect! sq is already evaluated
println(sq)
Surprisingly, this will print 4 and not 9! val (even var) is evaluated immediately and assigned.
Now change val to def.. it will print 9! Def is a function call.. it will evaluate each time it is called.
令人惊讶的是,这将打印 4 而不是 9!val(甚至var)被立即评估并分配。
现在将 val 更改为 def.. 它会打印 9!Def 是一个函数调用。它会在每次被调用时求值。
回答by Sandi
val i.e. "sq" is by Scala definition is fixed. It is evaluated right at the time of declaration, you can't change later. In other examples, where even2 also val, but it declared with function signature i.e. "(Int => Boolean)", so it is not Int type. It is a function and it's value is set by following expression
val 即“sq”是由 Scala 定义固定的。它在声明时进行评估,以后无法更改。在其他例子中,even2 也是 val,但它声明了函数签名,即“(Int => Boolean)”,所以它不是 Int 类型。它是一个函数,它的值由以下表达式设置
{
println("val");
(x => x % 2 == 0)
}
As per Scala val property, you can't assign another function to even2, same rule as sq.
根据 Scala val 属性,您不能将另一个函数分配给 even2,与 sq 相同的规则。
About why calling eval2 val function not printing "val" again and again ?
关于为什么调用 eval2 val 函数不会一次又一次地打印“val”?
Orig code:
原文代码:
val even2: (Int => Boolean) = {
println("val");
(x => x % 2 == 0)
}
We know, in Scala last statement of above kind of expression (inside { .. }) is actually return to the left hand side. So you end up setting even2 to "x => x % 2 == 0" function, which matches with the type you declared for even2 val type i.e. (Int => Boolean), so compiler is happy. Now even2 only points to "(x => x % 2 == 0)" function (not any other statement before i.e. println("val") etc. Invoking event2 with different parameters will actually invoke "(x => x % 2 == 0)" code, as only that is saved with event2.
我们知道,在 Scala 中,上述类型表达式的最后一条语句(inside { .. })实际上是返回到左侧。所以你最终将 even2 设置为 "x => x % 2 == 0" 函数,它与你为 even2 val 类型声明的类型 ie (Int => Boolean) 匹配,所以编译器很高兴。现在 even2 只指向 "(x => x % 2 == 0)" 函数(在即 println("val") 等之前没有任何其他语句。使用不同的参数调用 event2 实际上会调用 "(x => x % 2 == 0)" 代码,因为只有它与 event2 一起保存。
scala> even2(2)
res7: Boolean = true
scala> even2(3)
res8: Boolean = false
Just to clarify this more, following is different version of the code.
为了更清楚地说明这一点,以下是不同版本的代码。
scala> val even2: (Int => Boolean) = {
| println("val");
| (x => {
| println("inside final fn")
| x % 2 == 0
| })
| }
What will happen ? here we see "inside final fn" printed again and again, when you call even2().
会发生什么 ?在这里,当您调用 even2() 时,我们会看到一次又一次地打印“inside final fn”。
scala> even2(3)
inside final fn
res9: Boolean = false
scala> even2(2)
inside final fn
res10: Boolean = true
scala>
回答by Gaurav Khare
Executing a definition such as def x = ewill not evaluate the expression e. In- stead e is evaluated whenever x is invoked.
执行诸如此类的定义def x = e不会计算表达式 e。而是在调用 x 时评估 e。
Alternatively, Scala offers a value definition
val x = e,which does evaluate the right-hand-side as part of the evaluation of the definition.
If x is then used subsequently, it is immediately replaced by the pre-computed value of e, so that the expression need not be evaluated again.
或者,Scala 提供了一个值定义
val x = e,它确实将右侧作为定义评估的一部分进行评估。如果随后使用 x,则立即将其替换为 e 的预先计算值,因此无需再次计算表达式。
回答by prateek
In addition to the above helpful replies, my findings are:
除了上述有用的回复外,我的发现是:
def test1: Int => Int = {
x => x
}
--test1: test1[] => Int => Int
def test2(): Int => Int = {
x => x+1
}
--test2: test2[]() => Int => Int
def test3(): Int = 4
--test3: test3[]() => Int
The above shows that “def” is a method (with zero argument parameters) that returns another function "Int => Int” when invoked.
上面显示“def”是一个方法(带有零个参数),它在调用时返回另一个函数“Int => Int”。
The conversion of methods to functions is well explained here: https://tpolecat.github.io/2014/06/09/methods-functions.html
这里很好地解释了方法到函数的转换:https: //tpolecat.github.io/2014/06/09/methods-functions.html
回答by GraceMeng
In REPL,
在 REPL 中,
scala> def even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean
scala> val even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean = $$Lambda57/1017502292@57a0aeb8
def means call-by-name, evaluated on demand
def 表示call-by-name,按需评估
val means call-by-value, evaluated while initialization
val 表示call-by-value,在初始化时计算
回答by Sandipan Ghosh
also, Val is a by value evaluation. Which means the right-hand side expression is evaluated during definition. Where Def is by name evaluation. It will not evaluate until it's used.
此外,Val 是按值评估。这意味着在定义期间评估右侧表达式。其中 Def 是按名称评估。在使用之前不会对其进行评估。

