Scala高阶函数
Scala高阶函数官方文档
方法(Method)的官方文档:https://docs.scala-lang.org/scala3/book/methods-intro.html 【点next进入下一步】
函数(Function)的官方文档:https://docs.scala-lang.org/scala3/book/fun-intro.html【点next进入下一步】
一.函数 & 方法定义
- 方法定义:
- def 方法名(参数1:参数1类型, 参数2:参数2类型…):返回值类型 = { 函数体 }
scala> def f3(a:Int,b:Int):Int = a + b
f3: (a: Int, b: Int)Int
方法可以嵌套定义;
两个方法名称相同时,就近调用。
// 函数
object FunctionApp {
def main(args: Array[String]): Unit = {
def sayHi(name:String) ={
println(s"Hi, $name")
}
sayHi("Scala,1") // 就近调用sayHi方法, 输出结果:Hi, Scala,1
FunctionApp.sayHi("Scala,2") // 如果想调用外部定义的sayHi方法,输出结果:Hello, Scala,2
}
def sayHi(name:String) ={
println(s"Hello, $name")
}
sayHi("Flink,3") // 就近调用sayHi方法, 输出结果:Hello, Flink,3
}
/*
* 输出结果先后顺序:
Hello, Flink,3
Hi, Scala,1
Hello, Scala,2
*/
-
函数定义【下面函数的定义有点复杂,不用记忆】:
- 1)var/val 函数名 = (参数列表) => { 函数体 }
- 2)var/val 函数名:(参数1类型, 参数2类型…) => 返回值类型 = (参数1:参数1类型, 参数2:参数2类型…) => { 函数体 }
1)和 2)中函数的定义,最后都等价于**{函数体}**中的结果,如果只写 {函数体},就是匿名函数
// 函数两种定义,其实本质是一样的。都(Int,Int) => Int
scala> val f1 = (a:Int, b:Int)=> {
a + b }
f1: (Int, Int) => Int = $$Lambda$1032/378196591@656a3d6b
scala> val f2:(Int,Int) => Int = (a,b) => {
a + b }
f2: (Int, Int) => Int = $$Lambda$1048/517991921@251a90ce
===============================================
//上面两个都是这个匿名函数/匿名方法: (a,b)=>a+b
// 调用都是:f1(2,3) 和 f2(2,3)
二.函数和方法的相互转换
- 方法是一个特殊的函数(一等公民)两者之间相互调用,转换
- 函数转换成方法:直接转换
- 方法转换成函数:
- 1)= 方法名 _ (注意_前面有个空格)
- 2) ( _, _) 括号中有几个参数,就有几个下横线
- 3)直接转换,val 函数名:(参数1类型, 参数2类型…) => 返回值类型 = 方法名
// 函数转换成方法:直接转换
val f1Fun = (a:Int, b:Int) => {
a + b }
def fun = f1Fun
println(fun) // 输出结果:FunctionApp$$$Lambda$6/312116338@1b0375b3
println(fun(3,4))// 输出结果:7
// 方法转函数的3种方式
def f2(a:Int,b:Int):Int = {
a + b }
val f2Fun = f2 _ // 这里值需要写 空格&一个下划线
val f3Fun = f2(_,_) // 如果方法f2有几个参数,括号中需要写几个_
val f4Fun:(Int,Int)=>Int = f2 // 前面已经指定了函数的返回值类型((Int,Int)=>Int),后面就可以不用下划线了
println(f2Fun) // 输出结果:LamdaApp$$$Lambda$17/13648335@2f7c7260
println(f2Fun(5,6)) // 函数进行调用,输出结果:11
println(f3Fun) // 输出结果:LamdaApp$$$Lambda$18/312116338@2d209079
println(f3Fun(5,6)) // 函数进行调用,输出结果:11
println(f4Fun) // 输出结果:LamdaApp$$$Lambda$19/453211571@6bdf28bb
println(f4Fun(5,6)) // 函数进行调用,输出结果:11
三.函数的参数 & 返回值
- 无参的函数/方法
- 有固定参数的函数/方法
- 可变参数的函数/方法 【如果有固定参数, 可变参数放在参数列表最后】
- 默认值参数
// 1. 无参的函数/方法
def fun1() = {
println("hello,welcome to Scala") }
fun1() // 输出结果:hello,welcome to Scala
// 2. 有固定参数的函数/方法
def fun2(a: Int, b: Int) = {
println( a + b) }
fun2(3,4) // 输出结果:7
// 3. 可变参数的函数/方法
def fun31(b: Int*) = {
println(b) }
def fun32(a: Int, b: Int*) = {
println( s"a = $a, b = $b") }
fun31(5,6,7,8,9) // 输出结果:WrappedArray(5, 6, 7, 8, 9)
fun32(5,6,7,8,9) // 输出结果:a = 5, b = WrappedArray(6, 7, 8, 9)
// 4. 默认值参数
def fun4(name :String, age: Int) = {
println( s"name = $name, age = $age") }
fun4(age = 18, name = "scala") // 输出结果:name = scala, age = 18
Scala中至简原则(了解即可)
1)return可以省略,scala会使用最后一行代码作为返回值
2)如果函数体只有一行代码,{}可以省略
3)返回值类型如果能够推断,那么定义方法时候,返回值类型可以省略
4)如果有return,返回值类型不能省略,必须指定
5)如果函数指定返回值类型unit,即使函数体中使用了return关键字也不能返回结果
6)scala如果期望无返回值类型,可以省略等号(为了兼容Java等语法,个人不推荐这么写)
7)如果无参函数/方法,申明函数/方法时加了(),调用时,()可写可不写;
– def fun() = {…} , 调用时:fun 或者 fun()
8)如果无参函数/方法,申明函数/方法时没加(),调用时,()不能写;
9)如果不关心名称,那么函数名 和 def都可以省略【就是匿名函数】
– (a:Int, b:Int) => { a + b }
四.匿名函数/匿名方法 与 函数之间的关系
- 如果想给匿名函数/匿名方法加上名称,就出现函数的两种定义
(a:Int,b:Int) =>{
a + b} // 这是一个匿名方法
//在IDEA中,输入上面的匿名函数,自动转换成下面的带名称的函数
val fun1: (Int, Int) => Int = (a: Int, b: Int) => {
a + b}
val fun2 = (a: Int, b: Int) => {
a + b}
//fun1 和 fun2 等价, 两种不同写法
// 函数调用
fun1(3,