day03 Scala函数
一、创建函数
package day01 object Functions { def main(args: Array[String]): Unit = { //val maxF = max _的意思是将max函数赋值给名为maxF的变量, //但是在这里max后面添加了一个下划线 _,表示将函数的类型转换为函数值的类型 val maxFunc = max _ println(maxFunc(1, 2)) println(fac(6)) println(getIndex(Array[Int](1, 2, 3, 4), 3)) } /*1、两个值找最大值*/ def max(a:Int,b:Int):Int = { if(a > b) a else b } /*2、取绝对值*/ def abs(a:Int):Int = { // -a中的-表示前缀操作符 if(a < 0) -a else a } /*3、找目标值在数组中的下标位置*/ def getIndex(arr:Array[Int],tar:Int):Int={ // 也是用递归,循环找数组中的值,index是数组下表 def loop(index:Int):Int={ // 调用loop时,将index设为0,1、从第一个数查,如果相等返回当前下标 // 2、如果不相等,index+1作为loop参数,继续调用loop // 3、直到数组下标超过数组长度,返回-1 if (index >= arr.length){ -1 // arr(index)表示当前下标的元素值 }else if (arr(index) == tar){ index }else { // 继续查找对比 loop(index+1) } } loop(0) } /*4、阶乘,使用递归(自己调自己)*/ def fac(a:Int):Int = { // 递归:自己调自己 // acc表示结果集 def loop(n:Int,acc:Int):Int={ if(n ==1) acc // 继续调用loop,形成了循环,当n减到1,直接输出结果 // 先输入(5,1)loop(5,1)==>loop(4,5)==>loop(3,20)==>loop(2,60)==>loop(1,120) else loop(n-1,acc*n) } loop(a,1) } /*阶乘的另一个方法*/ def fac1(a:Int):Int={ if (a ==1 ) 1 else fac1(a-1)*a } def formatAbs(num: Int): Unit = { val msg: String = "source data = %d,abs(num)=%d" println(msg.format(num, abs(num))) } def formatMax(num:Int,num2:Int):Unit={ val msg: String="source data = %d,%d,max(num)=%d" println(msg.format(num,num2,max(num,num2))) } }
二、高阶函数--泛化函数
当一个函数被多次调用时,我们可以将这个函数写成泛化函数
/* * 参数列表:1、num:Int表示输入的数字 * 2、funcName:String一个字符串 * 3、funct:Int=>Int 定义一个方法,输入int类型,输出int类型,方法名为funct * funct表示自定义的方法名, * Int表示输入的参数类型, * =>表示执行函数, * Int表示执行完函数返回的数据类型 * */ def format(num: Int, funcName: String, funct: Int => Int): Unit = { // %s表示字符串占位符 val msg = "use %s conver %d to %d" println(msg.format(funcName, num, funct(num)))//use max conver -2 to 2 }
案例
package day01 object Functions { def main(args: Array[String]): Unit = { //val maxF = max _的意思是将max函数赋值给名为maxF的变量, //但是在这里max后面添加了一个下划线 _,表示将函数的类型转换为函数值的类型 val maxFunc = max _ println(maxFunc(1, 2)) println(fac(6)) println(getIndex(Array[Int](1, 2, 3, 4), 3)) println("========================泛化函数转换============================") format(5,"fac函数",fac) format1(-3,abs) format2(3,2,"max",max) } /*1、两个值找最大值*/ def max(a:Int,b:Int):Int = { if(a > b) a else b } /*2、取绝对值*/ def abs(a:Int):Int = { // -a中的-表示前缀操作符 if(a < 0) -a else a } /*3、找目标值在数组中的下标位置*/ def getIndex(arr:Array[Int],tar:Int):Int={ // 也是用递归,循环找数组中的值,index是数组下表 def loop(index:Int):Int={ // 调用loop时,将index设为0,1、从第一个数查,如果相等返回当前下标 // 2、如果不相等,index+1作为loop参数,继续调用loop // 3、直到数组下标超过数组长度,返回-1 if (index >= arr.length){ -1 // arr(index)表示当前下标的元素值 }else if (arr(index) == tar){ index }else { // 继续查找对比 loop(index+1) } } loop(0) } /*4、阶乘,使用递归(自己调自己)*/ def fac(a:Int):Int = { // 递归:自己调自己 // acc表示结果集 def loop(n:Int,acc:Int):Int={ if(n ==1) acc // 继续调用loop,形成了循环,当n减到1,直接输出结果 // 先输入(5,1)loop(5,1)==>loop(4,5)==>loop(3,20)==>loop(2,60)==>loop(1,120) else loop(n-1,acc*n) } loop(a,1) } /*阶乘的另一个方法*/ def fac1(a:Int):Int={ if (a ==1 ) 1 else fac1(a-1)*a } def form():Unit={println("=====================格式转换=======================")} def formatAbs(num: Int): Unit = { val msg: String = "source data = %d,abs(num)=%d" println(msg.format(num, abs(num))) } def formatMax(num:Int,num2:Int):Unit={ val msg: String="source data = %d,%d,max(num)=%d" println(msg.format(num,num2,max(num,num2))) } def form1():Unit={println("=====================泛化函数:公共的转换=======================")} /* * 参数列表:1、num:Int表示输入的数字 * 2、funcName:String一个字符串 * 3、funct:Int=>Int 定义一个方法,输入int类型,输出int类型,方法名为funct * funct表示自定义的方法名, * Int表示输入的参数类型, * =>表示执行函数, * Int表示执行完函数返回的数据类型 * */ def format(num: Int, funcName: String, funct: Int => Int): Unit = { // %s表示字符串占位符 val msg = "use %s conver %d to %d" println(msg.format(funcName, num, funct(num)))//use max conver -2 to 2 } /**/ def format1(num: Int, fun: Int => Int): Unit = { val msg = "use function conver %d to %d" println(msg.format(num, fun(num))) } /*两个参数的格式化*/ def format2(num:Int,num2:Int,functioin:String,fun:(Int,Int)=>Int):Unit={ val msg="%d,%d使用%s函数得出的结果为:%d" println(msg.format(num, num2, functioin,fun(num, num2))) } }
三、高阶函数--多态函数(泛型函数)
把针对单个类型的函数运用到可以针对多个类型,函数名后面加上泛型[A]
1、正常的函数形式
package day01 object MultiMode { // 正常模式,判断数组中是否含有目标值 def arrayContain(arr:Array[Int],tar:Int):Boolean={ def loop(index:Int):Boolean={ if (index >= arr.length){ false }else if (arr(index) == tar){ true }else{ loop(index +1) } } // 使用loop函数,从索引0开始 loop(0) } def main(args: Array[String]): Unit = { println(arrayContain(Array[Int](1,2, 3, 4, 5), 5)) } }
2、多态函数
相当于写一个模板,里面的类型用A表示,A可以是任何参数
案例1:判断一个值是否存在数组中
/* * 两个参数:一个数组和一个函数 * 1、数组中元素类型在调用时可以定义 * 2、函数参数func:(A=>Boolean):表示这个形参func函数是输入一个A类型的数,返回Boolean类型的值 * 但是具体怎么执行,等调用这个函数时,用具体的执行方式来替换这个形参 * */ def arrayMulti[A](arr:Array[A],func:A=>Boolean):Boolean={ def loop(index:Int):Boolean={ if (index >= arr.length){ false // 表示调用这个形参返回的Boolean值,具体是什么执行方法,在调用时写出来,但不管怎么写,arr(index)就是写的函数形参的参数 }else if (func(arr(index))){ true }else{ loop(index +1) } } // 使用loop函数,从索引0开始 loop(0) } def main(args: Array[String]): Unit = { /*第二个参数应该是一个函数 def func(x:Int):Boolean={ if (x == 5) true else false } 这个func咱们简写了,func在loop函数被多次循环调用时,参数x就是arr(index) */ // (x: Int) => x == 5 println(arrayMulti(Array[Int](1, 2, 3, 4), (x: Int) => x == 5)) println(arrayMulti(Array[String]("a", "b", "c"), (x: String) => x.equals("b"))) }
案例2:判断一个数组是否是升序(或降序)排列
package day01 object MultiMode { /*多态函数 * 判断这个数组是否是升序(后降序)排列 * */ def multi[A](ar:Array[A],func:(A,A)=>Boolean):Boolean={ /* 逻辑:从索引0开始,0>= 4,false,不返回true,继续向下1<2,正确,但是前面加了!,所以还不返回,继续执行索引1 直到 6<5,错误,取反后为true,则返回false,结果就是false */ def loop(index:Int):Boolean={ //表示查到末尾还没返回false,则整个数组就是正确的排序,中途有错误的,直接就返回false了,执行不到这里了 if (index >= ar.length -1) true // 顺序正确,就取反让其不返回false,继续查找,直到顺序不正确,取反if条件就成功执行,返回了false else if (!func(ar(index),ar(index + 1))) false // 继续查找 else loop(index + 1) } loop(0) } def main(args: Array[String]): Unit = { println(multi[Int](Array[Int](1, 2, 3, 6, 5), (x: Int, y: Int) => x <= y)) } }
返回值是函数的案例
def currying(x:Int,func:(Int,Int)=>Int):Int=>Int={ // 返回值是个函数Int=>Int,所以要传值一个Int类型的值,结果为Int类型(刚好func参数就是返回的Int值,所以借用func函数) // (y:Int) => func(x,y)这个就是一个匿名函数,符合返回一个函数的要求 // 传一个Int值 (y:Int) => func(x,y) } /* * 两个参数:1、一个A类型的数值 * 2、一个类型A和类型B生成一个类型C的函数 * 返回值:一个类型B生成一个类型C的函数 * 方法体:一个匿名函数:传一个类型B的值生成(由上面函数形参func生成的类型C数据)类型C数据 * */ def currying1[A,B,C](a:A,func:(A,B)=>C):B=>C={ (b:B)=>func(a,b) } def main(args: Array[String]): Unit = { // currying(2, (x: Int, y: Int) => x + y) 返回的这个表达式是函数 val int_int = currying(2, (x: Int, y: Int) => x + y) println(int_int(4))//6 val cur = currying1[Int,Int,String](5,(a:Int,b:Int)=> s"${a}${b}") println(cur(20))//520 }
四、柯里化函数(Currying)
将参数分开,每个参数都形成了一个函数
作用:协助编译器进行类型推断
/*正常函数*/ def noCurry(x:Int,y:Int):Int={ x + y } /*柯里化函数*/ def curry(x:Int)(y:Int):Int={ x + y } def main(args: Array[String]): Unit = { println(noCurry(2, 3)) println(curry(1)(3)) }
高阶案例
/* * 这个函数就是柯里化函数的证明过程 * 返回值就相当于:A=>(B=>C),因为函数是偏右法则,所以()省略了 * A赋值1,B赋值2,流程就是:f(1)结果是一个函数(类型A生成) * */ def curri[A,B,C](f:(A,B)=>C):A=> B=>C={ // 相当于(a:A)=>{(b:B)=> f(a,b)} (a:A)=> (b:B)=>f(a,b) } /* * 这个函数就是柯里化函数的反证明过程 * */ def recurr[A,B,C](f:A=>B=>C):(A,B)=>C={ (a:A,b:B)=> f(a)(b) } def main(args: Array[String]): Unit = { val func = curri[Int,Int,Int]((x:Int,y:Int)=> x+y) println(func)//是一个函数 println(func(3))//也是一个函数 println(func(3)(2))//5 }
案例
def arrayMulti[A](arr: Array[A])(func: A => Boolean): Boolean = { def loop(index: Int): Boolean = { if (index >= arr.length) { false // 表示调用这个形参返回的Boolean值,具体是什么执行方法,在调用时写出来,但不管怎么写,arr(index)就是写的函数形参的参数 } else if (func(arr(index))) { true } else { loop(index + 1) } } // 使用loop函数,从索引0开始 loop(0) } def main(args: Array[String]): Unit = { // 第二个参数本来应该是(x:Int=> x == 5), // 因为是柯里化函数,第二个参数的入参类型可以省略了 println(arrayMulti(Array(2, 3, 4, 5, 7))(x => x == 5)) }