好程序員大數據學習路線分享高階函數,我們通常將可以做爲參數傳遞到方法中的表達式叫做函數
高階函數包含:作爲值的函數、匿名函數、閉包、柯里化等等。
定義函數時格式:val 變量名 = (輸入參數類型和個數) => 函數實現和返回值類型和個數
“=”表示將函數賦給一個變量
“=>”左面表示輸入參數名稱、類型和個數,右邊表示函數的實現和返回值類型和參數個數
作爲值的函數
定義函數
scala> val func = (x:Int) => x * x
func: Int => Int = <function1>
scala> val func:Int => Int = x => x * x
func: Int => Int = <function1>
scala> func(3)
res0: Int = 9
函數調用
scala> val arr = Array(1,2,3,4)
arr: Array[Int] = Array(1, 2, 3, 4)
scala> val res = arr.map(x => func(x))
res: Array[Int] = Array(1, 4, 9, 16)
scala> val res = arr.map(func(_))
res: Array[Int] = Array(1, 4, 9, 16)
scala> val res = arr.map(func)
res: Array[Int] = Array(1, 4, 9, 16)
將方法轉化爲函數
scala> def m1(x:Int):Int = x * x
m1: (x: Int)Int
scala> def m1(x:Int) = x * x
m1: (x: Int)Int
scala> def m2(x:Int) {x * x}
m2: (x: Int)Unit
scala> val f1 = m1 _
f1: Int => Int = <function1>
scala> val res = arr.map(x => m1(x))
res: Array[Int] = Array(1, 4, 9, 16)
scala> val res = arr.map(m1(_))
res: Array[Int] = Array(1, 4, 9, 16)
scala> val res = arr.map(m1)
res: Array[Int] = Array(1, 4, 9, 16)
匿名函數
在Scala中,你不需要給每一個函數命名,沒有將函數賦給變量的函數叫做匿名函數
scala> arr.map((x:Int) => x * x)
res3: Array[Int] = Array(1, 4, 9, 16)
scala> arr.map(x => x * x)
res4: Array[Int] = Array(1, 4, 9, 16)
scala> arr.map(m1)
res1: Array[Int] = Array(1, 4, 9, 16)
scala> arr.map(_ * 2)
res2: Array[Int] = Array(2, 4, 6, 8)
閉包
閉包就是能夠讀取其他函數內部變量的函數
可以理解成,定義在一個函數內部的函數
本質上,閉包是將函數內部和函數外部鏈接起來的橋樑
object Bibao {
def sum(f:Int => Int):(Int,Int) => Int = {
def sumf(a:Int,b:Int):Int = {
if (a > b) 0 else f(a)+sumf(a + 1,b)
}
sumf //隱式轉換成函數
}
def main(args: Array[String]): Unit = {
def sumInts = sum(x => x)
println(sumInts(1,2))
}
}
柯里化
柯里化指的是將原來接收兩個參數列表的方法或函數變成新的一個參數列表的方法或函數的過程
聲明和轉化
scala> def curry(x:Int)(y:Int) = x * y //聲明
curry: (x: Int)(y: Int)Int
scala> curry(3)(4)
res8: Int = 12
scala> val curry1 = curry(3) //轉換成方法 : 加""
curry1: Int => Int = <function1>
scala> curry1(5)
res9: Int = 15
scala> def curry2(x:Int) = (y:Int) => x * y //聲明
curry2: (x: Int)Int => Int
scala> val func = curry2(2) //直接轉化
func: Int => Int = <function1>
scala> func(4)
res16: Int = 8
scala> def curry3() = (x:Int) => x * x
curry3: ()Int => Int
scala> val func = curry3() //轉化空參
func: Int => Int = <function1>
scala> func(3)
res17: Int = 9
柯里化需要與隱式轉換相結合
implicit 隱式的 -> 隱式值在當前會話中同類型只能定義一次,不同類型可定義多個
scala> def m1(x:Int)(implicit y:Int=5) = x * y
m1: (x: Int)(implicit y: Int)Int
scala> m1(3)
res10: Int = 15
scala> m1(3)(6) //隱式值可以改變
res11: Int = 18
scala> implicit val x = 100 //定義成全局的隱式值,可以覆蓋
x: Int = 100
scala> m1(3)(6)
res12: Int = 18
scala> m1(3)
res13: Int = 300
scala> implicit val y = "abc"
y: String = abc
案例: 把數組中元祖的value相加
scala> val arr = Array(("xixi",1),("haha",2),("heihei",3))
arr: Array[(String, Int)] = Array((xixi,1), (haha,2), (heihei,3))
scala> arr.foldLeft(0)( + ._2) //(初始值)(上次計算結果+循環出的結果)
res15: Int = 6
Curry的Demo
object Context{ //一般情況會新建類,再在此地調用
implicit val a = "yaoyao"
implicit val b = 100
}
object Curry {
//與變量沒有關係,系統自己匹配相同類型的值
implicit val a = "yaoyao"
implicit val b = 100
def m1(str:String)(implicit name:String="xiaodan"){
println(str + name)
}
def main(args: Array[String]): Unit = {
import Context.a
m1("Hello ")
}
}
隱式轉換
作用: 隱式的對類的方法進行增強,豐富現有類庫的功能
隱式轉換:
繼承 -> 通過方法的重寫來對父類的方法增強
代理模式 -> 遠程代理,多用於網站,代理一個實例,可以對實例方法增強,在調用方法之前
代理,方法之後環繞
裝飾模式 -> 裝飾模式也叫包裝模式,用java讀取文件時要用到IO流,也是對實例方法增強
new BufferInputStream(new FileInputStream).read()
就是用到了裝飾模式和門面模式 ->
裝飾模式是顯示的包裝,隱式轉換就是隱式的做了包裝
門面模式起到了隱式包裝的作用
隱式轉換函數 : 是指以implicit關鍵字聲明的帶有單個參數的函數
案例: 用隱式轉換,實現從給定的URI直接能調用read方法讀取文件內容
object MyPredef {
//implicit def fileToRichFile(file:String) = new RichFile(file)
implicit val fileToRichFile = (file:String) =>new RichFile(file)
}
object RichFile {
def main(args: Array[String]): Unit = {
val file = "e://wordcount.txt"
// //顯示的實現了對file的方法增強
// val richFile = new RichFile(file)
// val content: String = richFile.read()
// println(content)
//隱式轉換
import MyPredef.fileToRichFile
val content = file.read()
println(content)
}
}
class RichFile(val file:String){
//創建read方法
def read():String = {
Source.fromFile(file).mkString
}
}