一、函数与方法的区别
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
三、函数至简原则
- 给出一个原始函数
def calc(a:Int):Int ={ return a+1 }
- return可以省略,函数最后一行代码作为返回值
def calc(a:Int):Int ={ a+1 }
- 函数体只有一行代码,可以省略{}
def calc(a:Int):Int = a+1
- 如果返回值类型可以推断处理,那么这里的:和返回值类型都可以省略,这里如果写了return的话,那就不能省略了
def calc(a:Int) = a+1
- 如果不关心函数名的话,那么def和函数名都可以省略,但是=要变成=>,这就是匿名函数;
(a:Int) => {a+1}
- 如果返回值为Unit,那么return即使写了也是无效的;
- Scala如果期望是无返回值类型,那么可以省略等号(=),这里跟Java中的类似
- 如果参数列表为空的话,那么调用的时候可以不写();声明的时候如果不写(),但是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'))
}