《Scala by Example》第四章_表达式和函数
4.2 参数
- 用保留字 def 做定义的,如def x = e ,不会直接对e进行估值,而是等到x被使用的时候,再对e进行估值(evaluate)
- 而用val 进行定义的值,会直接计算值,然后在变量被使用的时候,用这个值代替这个变量
- Scala默认是使用“值传递”(call-by-value),不过在使用 “=>”之后,会转换成为“字面量传递”(call-by-name)
4.3 条件表达式
- 就是if-else,跟Java差不多,也就是那么用的。
4.4 例子:用牛顿算法求平方根
目的是写一个函数,类似于下面这样:
def sqrt(x : Double) : Double = ...
用来计算x的平方根。
首先,定义一个函数用来从最初的猜想(guess)到最后的结果(result)进行迭代求值,代码如下:
def sqrtIter(guess : Double , x : Double) : Double =
if (isGoodEnough(guess , x )) guess
else sqrtIter(improve(guess , x) , x )
这里用到了递归。而在函数式语言中,“递归”会经常用到。(还有一个名词叫“尾递归”,可以用来代替while循环)。
在这个函数中,还有一个返回类型:Double。它是跟在参数列表部分后的。在一个递归函数中,返回类型是强制需要的;对于一个非递归函数,返回类型是可选的。因为类型检查器会从函数右侧推断出函数类型。但即便是这样,写上返回类型也是一件好事。这样代码更有可读性。
其次,定义两个被调用的函数:一个用来改进guess的函数(inprove)和一个最终判断的函数(isGoogEnough)。以下是定义:
def improve(guess : Double , x : Double) = (guess + x / guess) / 2
def isGoodEnough(guess : Double , x : Double) =
abs(square(guess) - x ) < 0.001
最后,求根函数(sqrt)自己也是由sqrtIter来定义的:
def sqrt(x : Double) = sqrtIter(1.0 , x)
注:想要正常运行这些代码的前提是要import scala.Math._ 这样才可以使用abs函数。同样,square方法没有找到。最后直接用guess * guess来表示的。
4.5 嵌套函数
- 为了避免这个函数的使用者看到其它我们自己写的Helper函数,可以把这些Helper函数写在最外的函数里面。这样就形成了嵌套函数(nested Functions)。
- Scala使用通常用的块结构范围法则(scoping rules)。在外面定义的名字,可以在块内部也可以被看到。
4.6 尾递归(tail recursion)
定义:通常来说,如果一个函数最后的动作是调用另外一个(也可能是同一个)函数,对于两个函数而言,只需要一个堆空间,这样的调用就是尾调用。
尾递归,从一点点的分析来看,它所需的Stack空间并没有增多。而比如像“阶乘”这样的运算,它所需的Stack空间是增加的。所以它不是尾递归。
浙公网安备 33010602011771号