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))
}
本文介绍了Scala中的函数定义,包括基本函数、高阶函数(如泛化函数、多态函数和柯里化),以及递归和数组操作的示例。通过实例展示了如何创建和应用这些函数,以及它们在代码复用和类型推断中的作用。
1612

被折叠的 条评论
为什么被折叠?



