[Scala03]求值策略、函数、柯里化
1、求值策略(evaluation strategy)
在scala中,所有的运算都是基于表达式的,我们要对运算进行求值,会有不一样的方法和策略。
在scala有两种不同的求值策略,一种叫call by value(严格求值),一种叫call by name(非严格求值)。
1)call by value:对函数实参进行求值,且仅求值一次
2)call by name:函数实参每次都函数体内被用到都会求值
3)scala通常使用call by value,如果函数形参类型使用=>开头,则会使用call by name
call by name 和call by value在不同场景下性能优劣不同,以上例子左边call by valuex性能更高,右边call by name性能更高
scala> def bar(x:Int,y: =>Int):Int=1
bar: (x: Int, y: => Int)Int
scala> def loop():Int=loop
loop: ()Int
scala> bar(1,loop)
res1: Int = 1
scala> bar(loop,1)
2、scala函数与匿名函数
1)函数可以作为参数传递给另一个函数、函数可以作为返回值、函数可以赋给变量、函数可以存储在数据结构中
2)函数类型:
函数类型格式为A=>B,表示这个函数接受的参数类型为A,经过一系列的函数变换,返回值为类型B
例子:Int=>String 把整型映射为字符串类型的函数类型
3)高阶函数:用函数作为形参或返回值的函数,我们称之为高阶函数
scala> def operate(f:(Int,Int) =>Int):Int=f(3,5)
operate: (f: (Int, Int) => Int)Int
scala> operate((x,y) => x+y)
res4: Int = 8
#operate函数接受的参数为函数f,函数f的函数类型为(Int,Int) =>Int
#函数形参为函数时,传参格式传参格式参照上式
4)匿名函数(anonymous function)
匿名函数就是函数常量,也叫函数文字量
格式:
(形参列表)=>{函数体}
举例:
scala> (x: Int) => x*x
res5: Int => Int = <function1>
scala> (x: Int,y: Int) => x+y
res6: (Int, Int) => Int = <function2>
scala> var add=(x:Int,y:Int)=>x+y
add: (Int, Int) => Int = <function2>
scala> add(1,2)
res7: Int = 3
scala> def greeting() = (name:String) => {s"Hello $name"}
greeting: ()String => String
scala> greeting()("World")
res8: String = Hello World
#将匿名函数赋给另一个函数后,调用该函数时的正确方式用红色字体注明
3、柯里化(curried function)
柯里化函数把具有多个参数的函数转换为一条函数链,每个节点上都是单一函数
将def add(x:Int,y:Int)=x+y化成def add(x:Int)(y:Int)=x+y叫柯里化函数,这两个函数等价
4、递归函数(recursive function)
递归函数是函数式编程中一门非常重要的技术
scala> def factorial(n:Int):Int={if(n<=0)1 else n*factorial(n-1)}
factorial: (n: Int)Int
scala> factorial(3)
res9: Int = 6
#以上的递归容易造成堆栈溢出,所以我们尾递归函数对递归进行优化
尾递归函数:
尾递归函数中所有递归形式的调用都出现在函数的末尾,当编译器检测当当前递归函数的调用是尾递归时,它会覆盖当前的活动记录而不是在栈中创建一个新的
scala> @annotation.tailrec
| def factorial(x:Int,y:Int):Int={
| if(x<=0)y
| else factorial(x-1,x*y)}
factorial: (x: Int, y: Int)Int
scala> factorial(3,1)
res11: Int = 6
5、综合性例子