函数与Scala中的方法
我正在看Runar Bjarnason介绍初学者的函数式编程 ,14:45他定义了一个方法:
def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0
和一个function:
val isEven = isDivisibleBy(2)
定义isEven
作为一个函数而不是一个方法有什么好处和坏处?
我已经阅读了Scala函数与方法以及Scala中的方法和函数之间的区别 ,并且我理解语义差异,但是我不知道在这种情况下,为什么函数可能会或可能不会使用方法更好:
def isEven = isDivisibleBy(2)
在引擎盖下,function和方法还有其他的区别。 一般来说,一个普通的方法产生的开销比一个函数(技术上是一个具有apply
方法的对象)less。
然而,如果你不关心这些差异,并把def
, val
和var
当作不同语义的字段 ,那么简单地说就是def
每次被调用的时候评估,而val
只评估一次。
因此, val isEven = isDivisibleBy(2)
应该在其定义期间调用isDivisibleBy(2)
并指定isDivisibleBy(2)
的结果。 例如,它取代了k
def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0
与2
并分配最终expression式的结果(在这种情况下,只有一个expression式):
val isEven: Int => Boolean = i => i % 2 == 0
def isEven
另一方面没有这样的评价,并且每次都会调用isDivisibleBy(2)。
这意味着,稍后当您执行代码时, isEven(11)
在val
情况下生成
11 % 2 == 0
如果是def
,你会有的
isDivisibleBy(2)(11)
只有在评估isDivisibleBy
你会得到结果。
你可以添加一些debugging代码到isDivisibleBy
看看不同之处:
def isDivisibleBy(k: Int): Int => Boolean = { println("evaluating isDivisibleBy") i => i % k == 0 }
我想在这里谈谈另一点。 这将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)
被调用一次(在构build时,或者当定义中的行被执行时),并且每次调用isEven
时isEven
检索该值。 下面的例子只调用isDivisible(2)
:
val isEven = isDivisibleBy(2) List(1,2,3).filter(isEven)
我认为,定义函数的主要方法是将函数作为val
来向观众展示函数可以这样定义。 那么很明显,函数就像scala中的其他所有东西一样。 但在非演示编程的世界中,不需要写入函数作为val
。
方法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
来实现相同的结果def isEven(i: Int): Boolean = i % 2 == 0
我认为这个例子的意义在于,你可以有返回其他函数的函数,并且可以把函数存储为对象,然后像调用传统的方法一样调用它们。 上面的代码也和currying非常相似,所以这也可能是这个例子演示的一个东西(尽pipe它没有使用Scala的currying语法 )。