我在看Runar Bjarnason present Functional Programming for Beginners,在14:45他定义了一个方法:
def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0
和一个功能:
val isEven = isDivisibleBy(2)
将isEven
定义为函数而不是方法有哪些优缺点?
我已阅读Scala Functions vs Methods以及Difference between method and function in Scala,我理解语义差异,但我想知道在这种情况下是否有更深层次的原因为什么函数可能会或可能不会优于使用方法:
def isEven = isDivisibleBy(2)
答案 0 :(得分:58)
在幕后,功能和方法之间还存在其他差异。通常,普通方法产生的开销少于函数(技术上是具有apply
方法的对象)。
但是,如果您尝试不关心这些差异,并将def
,val
和var
视为具有不同语义的字段,那么它只是def
在每次调用val
时只评估一次{。}}。
因此,val isEven = isDivisibleBy(2)
应在定义期间调用isDivisibleBy(2)
并分配isDivisibleBy(2)
的结果。例如。它取代了<{p>中的k
def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0
使用2
并指定最终表达式的结果(在这种情况下只有一个表达式):
val isEven: Int => Boolean = i => i % 2 == 0
另一方面, def isEven
没有进行此类评估,每次都会调用isDivisibleBy(2)。
这意味着,稍后,当您执行代码时,isEven(11)
会生成val
11 % 2 == 0
如果是def
,您将拥有
isDivisibleBy(2)(11)
并且只有在评估isDivisibleBy
后才会得到结果。
您可以向isDivisibleBy
添加一些调试代码以查看差异:
def isDivisibleBy(k: Int): Int => Boolean = {
println("evaluating isDivisibleBy")
i => i % k == 0
}
答案 1 :(得分:16)
我想在这里谈另一点。这将isEven
定义为方法:
def isEven = isDivisibleBy(2)
这也将isEven
定义为一种方法:
val isEven = isDivisibleBy(2)
在这两种情况下,isEven
是一种方法,在调用时返回一个函数。
在第一种情况下,每次调用isDivisible(2)
时都会调用isEven
。例如,这会调用isDivisible(2)
三次:
def isEven = isDivisibleBy(2)
List(1,2,3).filter(isEven)
在第二种情况下,isDivisible(2)
被调用一次(在构造时,或者在执行定义中的那一行时),并且每次调用isEven
时都会检索该值。以下示例仅调用isDivisible(2)
一次:
val isEven = isDivisibleBy(2)
List(1,2,3).filter(isEven)
答案 2 :(得分:6)
我认为将函数isEven
定义为val
的主要原因是向观众展示可以通过这种方式定义函数。然后很明显,一个函数只是一个像scala中的其他东西一样的对象。但是在非演示编程的世界中,没有必要将函数编写为val
s。
答案 3 :(得分:3)
方法def isDivisibleBy(k: Int): Int => Boolean
返回一个函数,该函数将Int(i
)作为参数并返回一个布尔值(i % k == 0
)。
val isEven = isDivisibleBy(2)
是存储isDivisibleBy(2)
返回的函数的字段。如果使用def
而不是val
,则每次调用isEven方法时都会调用isDivisibleBy方法,但现在只调用一次,结果存储在字段中。
您可以通过撰写def isEven(i: Int): Boolean = i % 2 == 0
我认为该示例的要点是您可以拥有返回其他函数的函数,并且可以将函数存储为对象,然后将它们称为传统定义的方法。上面的代码也与currying非常相似,所以这也可能是示例所展示的一件事(尽管它不使用Scala's syntax for currying)。