有什么区别:
def even: Int => Boolean = _ % 2 == 0
and
val even: Int => Boolean = _ % 2 == 0
两者都可以称为偶数(10)。
有什么区别:
def even: Int => Boolean = _ % 2 == 0
and
val even: Int => Boolean = _ % 2 == 0
两者都可以称为偶数(10)。
当前回答
看到这个:
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)
令人惊讶的是,这将打印4而不是9!Val(甚至var)立即计算并分配。 现在将val改为def..它将打印9!Def是一个函数调用。它将在每次调用时求值。
其他回答
瓦尔。“sq”在Scala定义中是固定的。它是在声明时计算的,以后不能更改。在其他例子中,even2也是val,但它声明了函数签名,即。"(Int => Boolean)",所以它不是Int类型。它是一个函数,它的值由下面的表达式设置
{
println("val");
(x => x % 2 == 0)
}
根据Scala的val属性,你不能将另一个函数赋值给even2,这与sq规则相同。
关于为什么调用eval2 val函数不打印“val”一次又一次?
源自代码:
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> even2(2)
res7: Boolean = true
scala> even2(3)
res8: Boolean = false
为了更清楚地说明这一点,下面是不同版本的代码。
scala> val even2: (Int => Boolean) = {
| println("val");
| (x => {
| println("inside final fn")
| x % 2 == 0
| })
| }
会发生什么?在这里,当调用even2()时,我们看到“inside final fn”一遍又一遍地打印出来。
scala> even2(3)
inside final fn
res9: Boolean = false
scala> even2(2)
inside final fn
res10: Boolean = true
scala>
看到这个:
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)
令人惊讶的是,这将打印4而不是9!Val(甚至var)立即计算并分配。 现在将val改为def..它将打印9!Def是一个函数调用。它将在每次调用时求值。
方法def甚至在调用时计算并每次都创建新函数(Function1的新实例)。
def even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = false
val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true
使用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
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
注意,还有第三个选项:lazy val。
它在第一次调用时计算:
scala> lazy val even: Int => Boolean = ???
even: Int => Boolean = <lazy>
scala> even
scala.NotImplementedError: an implementation is missing
但每次都返回相同的结果(在这种情况下,相同的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
性能
Val在定义时求值。
Def对每个调用进行计算,因此对于多个调用,性能可能比val差。您将通过单个调用获得相同的性能。由于没有调用,你不会从def中得到任何开销,所以即使你不会在某些分支中使用它,你也可以定义它。
对于lazy val,您将得到一个lazy求值:即使您不会在某些分支中使用它,您也可以定义它,并且它只求一次或从不求值,但是由于对lazy val的每个访问进行双重检查锁定,您将获得一点开销。
正如@SargeBorsch指出的,你可以定义method,这是最快的选择:
def even(i: Int): Boolean = i % 2 == 0
但是如果你需要一个函数(而不是方法)来进行函数组合或更高阶的函数(如filter(甚至)),编译器将在你每次将它作为函数使用时从你的方法生成一个函数,因此性能可能比val略差。
考虑一下:
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
你看到区别了吗?简而言之:
对于even的每一次调用,它都会再次调用even方法的主体。但是对于even2,即val,函数在声明时只初始化一次(因此它在第4行打印val,再也不打印了),并且每次访问都使用相同的输出。例如,试着这样做:
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
当x被初始化时,由Random返回的值。nextInt被设置为x的最终值。下一次再次使用x时,它总是返回相同的值。
你也可以惰性初始化x,即第一次使用它时,它是初始化的,而不是在声明时。例如:
scala> lazy val y = { Random.nextInt }
y: Int = <lazy>
scala> y
res4: Int = 323930673
scala> y
res5: Int = 323930673
在REPL,
scala> def even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean
scala> val even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean = $$Lambda$1157/1017502292@57a0aeb8
Def表示按名称调用,按需计算
Val表示在初始化时按值调用