Scala函数、至简原则、高级函数、闭包/柯里化、隐式转换

一、函数与方法的区别

Scala中函数是一等公民,随处都可以定义函数;把定义在类或者对象下面的函数叫做方法;
也有一些解释两者没有区别,都叫做函数;

二、函数的声明

def functionName ([参数列表]) : [return type] = {
   function body
   return [expr]
}

例子1

def main(args: Array[String]): Unit = {
    //普通函数
    def sayHi(name: String): Unit = {
        println("hi "+name)
    }
    sayHi("joy")
    //变长参数必须放在参数列表中最后一位
    def sayHello(s:String*): Unit ={
         println("hello "+s.mkString(","))
    }
    sayHello("a")
    sayHello("a","b")
    //给参数赋默认值
    def sayHello2(s:String="joy",age:Int=10): Unit ={
        println("hello "+s+" ,age="+age)
    }
    sayHello2()
    sayHello2(age =18)
}

输出

hi joy

hello ab
hello a,b
hello joy ,age=10
hello joy ,age=18

三、函数至简原则

  1. 给出一个原始函数
def calc(a:Int):Int ={ return a+1 }
  1. return可以省略,函数最后一行代码作为返回值
def calc(a:Int):Int ={ a+1 }
  1. 函数体只有一行代码,可以省略{}
def calc(a:Int):Int = a+1
  1. 如果返回值类型可以推断处理,那么这里的:和返回值类型都可以省略,这里如果写了return的话,那就不能省略了
def calc(a:Int) = a+1
  1. 如果不关心函数名的话,那么def和函数名都可以省略,但是=要变成=>,这就是匿名函数;
(a:Int) => {a+1}
  1. 如果返回值为Unit,那么return即使写了也是无效的;
  2. Scala如果期望是无返回值类型,那么可以省略等号(=),这里跟Java中的类似
  3. 如果参数列表为空的话,那么调用的时候可以不写();声明的时候如果不写(),但是IDE一般会提示加上;
//简化前
def sayHello04():Unit = {
  println("hello joy")
}
//简化后
def sayHello05{
    println("hello joy")
}
sayHello05

为什么要使用匿名函数,它有啥优点,它适合哪些场景呢?

匿名函数结构简单,适合那种确认好了数据,但是需要执行不同操作的场景,所以它天然支持大数据操作;函数作为scala中的一等公民,自然也是符合OOP开发思想的,这里就会引入高阶函数,我们看一下匿名函数作为对象在高阶函数中的使用

四、高级函数

作为参数使用

def main(args: Array[String]): Unit = {
    val add = (a:Int,b:Int) =>{a+b}
    val subtract = (a:Int,b:Int) => {a - b}
    val multiply = (a:Int,b:Int) => {a * b}
    val divide = (a:Int,b:Int) => {a / b}
     
    def deal(fun:(Int,Int)=>Int): Int={
     fun(100, 10)
    }
    println("==========加法==============")
    println(deal(add))
    println("==========减法==============")
    println(deal(subtract))
    println("==========乘法==============")
    println(deal(multiply))
    println("==========除法==============")
    println(deal(divide))
}

再来分析一下匿名函数,这里是否还能继续简化呢,答案是可以的

//原匿名函数:(a:Int,b:Int) =>{a+b}
println(deal((a:Int,b:Int) => {a+b}))
//参数的类型可以省略,根据形参进行自动的推导;
println(deal((a,b) =>{a+b}))
//类型省略后,如果只有一个参数,那么参数的()可以省略;有多个参数和无参数的情况不能省略;
println(deal((a,b) =>{a+b}))
//如果函数只有一行,那么参数外的{}也可以省略
println(deal((a,b) => a+b))
//如果参数只出现一次,那么参数可以省略,且后面的参数可以用_代替
println(deal(_+_))

简化后我们上面的计算公式就变成了如下的样式

println(deal(_+_))
println(deal(_-_))
println(deal(_*_))
println(deal(_/_))

作为返回值使用

def main(args: Array[String]): Unit = {
    def deal(): Int => Unit = {
      def fun(a: Int): Unit = {
        println("函数作为返回值" + a)
      }
      fun
    }
    println(deal()(10))
}

五、闭包与柯里化

  • 闭包:一个函数,引用了它外部的数据,我们将这个整体称为一个闭包

  • 柯里化:将一个参数列表的多个参数,变成多个参数列表的过程称为函数柯里化;柯里化是闭包的一种表达方式,但是闭包不一定非得使用柯里化;

def main(args: Array[String]): Unit = {
    def deal(x:Int) = (y:Int) =>x+y
    /**
     * 闭包:一个函数,引用了它外部的数据,我们将这个整体称为一个闭包
     * 这里add2,add3都是闭包;
     */
    val add2 = deal(2)
    val add3 = deal(3)
    println("10+2="+add2(10))
    println("10+3="+add3(10))
    //柯里化的表达方式
    println("========柯里化的表达==============")
    def deal02(x:Int)(y:Int): Int = x+y
    println(deal02(2)(10))
  }

六、隐式转换

什么是隐式转换:Scala在进行第一次编译失败后,会在当前环境中寻找能编译通过个方法(这就是隐式转换),用于将类型进行转换进行二次编译;

object Demo08_yinshi {
  def main(args: Array[String]): Unit = {
    //1、隐式函数
    implicit def convert(a:Int): MyInt = new MyInt(a)
    println(100.maxInt(10))
    println(100.minInt(10))
    //2、隐式类
    implicit class MyInt2(val self:Int){
      def maxInt2(a:Int):Int = if (a > self) a else self
      def minInt2(a:Int):Int = if (a > self) self else a
    }
    println(100.maxInt2(10))
    println(100.minInt2(10))
    //3、隐式参数,相同类型是能定义一个
    implicit val str: String = "巴塞罗那"
    def sayHello(implicit s:String = "曼城"): Unit = println("hello "+s)
    //传入参数优先级最高
    sayHello("利物浦")
    //带()时,默认值比隐式参数优先级高
    sayHello()
    //不带(),隐式参数优先级高
    sayHello
  }
  class MyInt(val self:Int){
    def maxInt(a:Int):Int = if (a > self) a else self
    def minInt(a:Int):Int = if (a > self) self else a
  }
}

七、练习

练习一

给定一个数值数组,遍历该数组进行运算,如每个元素加10,每个元素翻倍

def main(args: Array[String]): Unit = {
  val arr = Array(30,40,60,100)
  //定义一个数组处理的函数
  def dealArray(array: Array[Int],op: Int =>Int): Array[Int] ={
    for(i<- array) yield op(i)
  }
  //定义具体数据处理的函数
  //数据加10
  val addTen: Int=>Int = a => a+10
  //数据翻倍
  val toDouble: Int=>Int = a =>a*2
  //函数调用
  println("===========addTen==================")
  println(dealArray(arr,addTen).mkString(","))
  println(dealArray(arr,_+1).mkString(","))
  println("===========toDouble==================")
  println(dealArray(arr,toDouble).mkString(","))
  println(dealArray(arr,_ * 2).mkString(","))
}

练习二

定义几组函数,这里fun_s的参数列表有一个String类型的参数s,fun_s作为fun_01的返回值,fun_01的参数列表有一个int类型的参数i;

fun_c作为fun_s的返回值,fun_c的参数列表有一个Char类型的参数c;

def main(args: Array[String]): Unit = {
    //1、定义一个函数,这里fun_s作为fun_01的返回值,fun_c作为fun_s的返回值
    def fun01(i: Int): String => Char => Boolean = {
      def fun_s(s: String): Char => Boolean = {
        def fun_c(c: Char): Boolean = {
          if (i == 0 && s == "" && c == '0') false else true
        }
        fun_c
      }
      fun_s
    }
    println(fun01(0)("")('0'))
    println(fun01(1)("")('0'))
    println(fun01(0)("hello")('0'))
    println(fun01(0)("")('a'))
    //2、使用匿名函数进行简化
    def fun02(i: Int): String => Char => Boolean = {
      s =>  c => if (i == 0 && s == "" && c == '0') false else true
    }
    println("==========匿名函数简化=========================")
    println(fun02(0)("")('0'))
    println(fun02(1)("")('0'))
    println(fun02(0)("hello")('0'))
    println(fun02(0)("")('a'))
    //3、柯里化:scala推荐使用的方式
    def fun03(i:Int)(s:String)(c:Char):Boolean ={
      if (i == 0 && s == "" && c == '0') false else true
    }
    println("=========柯里化==========================")
    println(fun03(0)("")('0'))
    println(fun03(1)("")('0'))
    println(fun03(0)("hello")('0'))
    println(fun03(0)("")('a'))
  }

猜你喜欢

转载自blog.csdn.net/csdn_tiger1993/article/details/125591011