有什么区别:
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)。
当前回答
在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表示在初始化时按值调用
其他回答
此外,Val是一个按值求值。这意味着右边的表达式在定义期间被求值。其中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略差。
除了上述有用的回复,我的发现是:
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
上面的例子表明,“def”是一个方法(参数为零),在调用时返回另一个函数“Int => Int”。
方法到函数的转换在这里有很好的解释:https://tpolecat.github.io/2014/06/09/methods-functions.html
执行像def x = e这样的定义不会求表达式e的值。相反,每当x被调用时,e都会被求值。
或者,Scala提供了一个值定义 Val x = e,它计算右边的值作为定义值的一部分。 如果随后使用x,则立即用预先计算的e值替换它,这样表达式就不需要再次求值。
在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表示在初始化时按值调用