一個集合val list = List(1,2,3,4,"abc"),完成以下要求編程
1) 將集合list中的全部數字+1,並返回一個新的集合閉包
2) 要求忽略掉非數字的元素,即返回的新的集合形式爲(2,3,4,5)app
object boke_demo01 { def main(args: Array[String]): Unit = { //思路1 filter + map 方式解決 //雖然能夠解決問題,可是麻煩. val list = List(1, 2, 3, 4, "hello") // 先過濾,再map println(list.filter(f1).map(f3).map(f2)) //思路2-模式匹配 //小結:雖然使用模式匹配比較簡單,可是不夠完美 val list2 = list.map(addOne2) println("list2=" + list2) } //模式匹配 def addOne2(i: Any): Any = { i match { case x: Int => x + 1 case _ => } } def f1(n: Any): Boolean = { n.isInstanceOf[Int] } def f2(n: Int): Int = { n + 1 } //將Any->Int [map] def f3(n: Any): Int = { n.asInstanceOf[Int] } }
-使用偏函數解決前面的問題ide
-案例演示函數
object boke_demo01 { def main(args: Array[String]): Unit = { //使用偏函數解決 val list = List(1, 2, 3, 4, "hello") //定義一個偏函數 //1. PartialFunction[Any,Int] 表示偏函數接收的參數類型是Any,返回類型是Int //2. isDefinedAt(x: Any) 若是返回true ,就會去調用 apply 構建對象實例,若是是false,過濾 //3. apply 構造器 ,對傳入的值 + 1,並返回(新的集合) val partialFun = new PartialFunction[Any, Int] { override def isDefinedAt(x: Any) = { println("x=" + x) x.isInstanceOf[Int] } override def apply(v1: Any) = { println("v1=" + v1) v1.asInstanceOf[Int] + 1 } } //使用偏函數 //說明:若是是使用偏函數,則不能使用map,應該使用collect //說明一下偏函數的執行流程 //1. 遍歷list全部元素 //2. 而後調用 val element = if(partialFun-isDefinedAt(list單個元素)) {partialFun-apply(list單個元素) } //3. 每獲得一個 element,放入到新的集合,最後返回 val list2 = list.collect(partialFun) println("list2" + list2) } }
1) 使用構建特質的實現類(使用的方式是PartialFunction的匿名子類)測試
2) PartialFunction是個特質scala
3) 構建偏函數時,參數形式[Any,Int]是泛型,第一個表示參數類型,第二個表示返回參數對象
4) 當使用偏函數時,會遍歷集合的全部元素,編譯器執行流程時先執行isDefinedAt(),若是爲true,就會執行apply,構建一個新的對象返回blog
5) 執行isDefinedAt()爲false就過濾掉這個元素,即不構建新的Int對象遞歸
6) map函數不支持偏函數,由於map底層的機制就是全部循環遍歷,沒法過濾處理原來集合的元素
7) collect函數支持偏函數
object boke_demo01 { def main(args: Array[String]): Unit = { //能夠將前面的案例的偏函數簡寫 def partialFun: PartialFunction[Any, Int] = { //簡寫成case 語句 case i: Int => i + 1 case j: Double => (j * 2).toInt } val list = List(1, 2, 3, 4, 1.2, 2.4, 1.9f, "hello") val list2 = list.collect(partialFun) println("list2=" + list2) //第二種簡寫形式 val list3 = list.collect { case i: Int => i + 1 case j: Double => (j * 2).toInt case k: Float => (k * 3).toInt } println("list3=" + list3) // (2,3,4,5) } }
函數做爲一個變量傳入到另外一個函數中,那麼該做爲參數的函數的類型是:function1,即:(參數類型) => 返回類型
object boke_demo01 { def main(args: Array[String]): Unit = { def plus(x: Int) = 3 + x //說明 val result = Array(1, 2, 3, 4).map(plus(_)) println(result.mkString(",")) //4,5,6,7 //說明 //1. 在scala中,函數也是有類型,好比plus就是 <function1> println("puls的函數類型function1" + (plus _)) } }
1) map(plus(_))中的plus(_)就是將plus這個函數看成一個參數傳給了map,_這裏表明從集合中遍歷出來的一個元素
2) plus(_)這裏也能夠寫成plus表示對Array(1,2,3,4)遍歷,將每次遍歷的元素傳給plus的x
3) 進行 3+x 運算後,返回新的Int,並加入到新的集合result中
4) def map[B,That](f:A=>B)的聲明中的 f:A=>B 的一個函數
沒有名字的函數就是匿名函數,能夠經過函數表達式來設置匿名函數
object boke_demo01 { def main(args: Array[String]): Unit = { //對匿名函數的說明 //1. 不須要寫 def 函數名 //2. 不須要寫返回類型,使用類型推導 //3. = 變成 => //4. 若是有多行,則使用{} 包括 val triple = (x: Double) => { println("x=" + x) 3 * x } println("triple=" + triple(3)) // 9.0 } }
可以接受函數做爲參數的函數,叫作高階函數(higher-order function)。可以使應用程序更加健壯
object boke_demo01 { def main(args: Array[String]): Unit = { def test(f: Double => Double, f2: Double => Int, n1: Double) = { f(f2(n1)) // f(0) } //sum 是接收一個Double,返回一個Double def sum(d: Double): Double = { d + d } def mod(d: Double): Int = { d.toInt % 2 } val res = test(sum, mod, 5.0) // println("res=" + res) // 2.0 } }
object boke_demo01 { def main(args: Array[String]): Unit = { //說明 //1. minusxy是高階函數,由於它返回匿名函數 //2. 返回的匿名函數 (y: Int) => x - y //3. 返回的匿名函數可使用變量接收 def minusxy(x: Int) = { (y: Int) => x - y //匿名函數 } //分步執行 //f1 就是 (y: Int) => 3 - y val f1 = minusxy(3) println("f1的類型=" + f1) println(f1(1)) // 2 println(f1(9)) // -6 //也能夠一步到位的調用 println(minusxy(4)(9)) // -5 } }
參數推斷省去類型信息(在某些狀況下[須要有應用場景],參數類型是能夠推斷出來的,如list=(1,2,3) list.map() map中函數參數類型是能夠推斷的),同時也能夠進行相應的簡寫
1) 參數類型是能夠推斷時,能夠省略參數類型
2) 當傳入的函數,只有單個參數時,能夠省去括號
3) 若是變量只在=>右邊只出現一次,能夠用_來代替
object boke_demo01 { def main(args: Array[String]): Unit = { val list = List(1, 2, 3, 4) println(list.map((x: Int) => x + 1)) //(2,3,4,5) println(list.map((x) => x + 1)) //(2,3,4,5) println(list.map(x => x + 1)) //(2,3,4,5) println(list.map(_ + 1)) //(2,3,4,5) println(list.reduce(f1)) // 10 println(list.reduce((n1: Int, n2: Int) => n1 + n2)) //10 println(list.reduce((n1, n2) => n1 + n2)) //10 println(list.reduce(_ + _)) //10 val res = list.reduce(_ + _) } def f1(n1: Int, n2: Int): Int = { n1 + n2 } }
閉包就是一個函數和與其相關的引用環境組合的一個總體(實體)
object boke_demo01 { def main(args: Array[String]): Unit = { //1.用等價理解方式改寫 2.對象屬性理解 def minusxy(x: Int) = (y: Int) => x - y //f 函數就是閉包. val f = minusxy(20) println("f(1)=" + f(1)) // 19 println("f(2)=" + f(2)) // 18 } }
-對上述案例演示的小結和說明
1) (y: Int) => x - y 返回的是一個匿名函數,由於該函數引用到函數外的x,那麼該函數和x總體造成一個閉包。如:這裏val f = minusxy(20)的f函數就是閉包
2) 能夠這樣理解,返回函數是一個對象,而x就是該對象的一個字段,它們共同造成一個閉包
3) 當屢次調用f時(能夠理解屢次調用閉包),發現使用的是同一個x,因此x不變
4) 在使用閉包時,主要搞清楚返回函數引用了函數外的哪些變量,由於它們會組合成一個總體(實體),造成一個閉包
object boke_demo01 { def main(args: Array[String]): Unit = { /* 請編寫一個程序,具體要求以下 1.編寫一個函數 makeSuffix(suffix: String) 能夠接收一個文件後綴名(好比.jpg),並返回一個閉包 2.調用閉包,能夠傳入一個文件名,若是該文件名沒有指定的後綴(好比.jpg) ,則返回 文件名.jpg , 若是已經有.jpg後綴,則返回原文件名。 好比 文件名 是 dog =>dog.jpg 好比 文件名 是 cat.jpg => cat.jpg 3.要求使用閉包的方式完成 提示:String.endsWith(xx) */ //使用並測試 val f = makeSuffix(".jpg") println(f("dog.jpg")) // dog.jpg println(f("cat")) // cat.jpg } def makeSuffix(suffix: String) = { //返回一個匿名函數,回使用到suffix (filename:String) => { if (filename.endsWith(suffix)) { filename } else { filename + suffix } } } }
1) 函數編程中,接受多個參數的函數均可以轉化爲接受單個參數的函數,這個轉化過程就叫柯里化
2) 柯里化就是證實了函數只須要一個參數而已
//編寫一個函數,接收兩個整數,能夠返回兩個數的乘積,要求: //使用常規的方式完成 //使用閉包的方式完成 //使用函數柯里化完成 def mul(x: Int, y: Int) = x * y println(mul(10, 10)) def mulCurry(x: Int) = (y: Int) => x * y println(mulCurry(10)(9)) def mulCurry2(x: Int)(y:Int) = x * y println(mulCurry2(10)(8))
object boke_demo01 { def main(args: Array[String]): Unit = { //這是一個函數,能夠接收兩個字符串,比較是否相等 def eq(s1: String, s2: String): Boolean = { s1.equals(s2) } //隱式類 implicit class TestEq(s: String) { //體現了將比較字符串的事情,分解成兩個任務完成 //1. checkEq 完轉換大小寫 //2. f函數完成比較任務 def checkEq(ss: String)(f: (String, String) => Boolean): Boolean = { f(s.toLowerCase, ss.toLowerCase) } } val str1 = "hello" println(str1.checkEq("HeLLO")(eq)) //在看一個簡寫形式 println(str1.checkEq("HeLLO")(_.equals(_))) } }
//如何實現將一段代碼(從形式上看),做爲參數傳遞給高階函數,在高階函數內部執行這段代碼 //其使用的形式如 breakable{} var n = 10 breakable { while (n <= 20) { n += 1 if (n == 18) { break() } } }
-控制抽象是這樣的函數,知足以下條件
1) 參數是函數
2) 函數參數沒有輸入值也沒有返回值
-控制抽象應用案例(使用控制抽象實現了while語法)
object boke_demo01 { def main(args: Array[String]): Unit = { //myRunInThread 就是一個抽象控制 //是沒有輸入,也沒有輸出的函數 f1: () => Unit def myRunInThread(f1: () => Unit) = { new Thread { override def run(): Unit = { f1() //只寫了 f1 } }.start() } myRunInThread { () => println("幹活咯!5秒完成...") Thread.sleep(5000) println("幹完咯!") } //簡寫形式 def myRunInThread2(f1: => Unit) = { new Thread { override def run(): Unit = { f1 //只寫了 f1 } }.start() } //對於沒有輸入,也沒有返回值函數,能夠簡寫成以下形式 myRunInThread2 { println("幹活咯!5秒完成...~~~") Thread.sleep(5000) println("幹完咯!~~~") } } }
object boke_demo01 { def main(args: Array[String]): Unit = { var x = 10 //說明 //1 函數名爲 until , 實現了相似 while循環的效果 //2. condition: => Boolean 是後一個沒有輸入值,返回Boolean類型函數 //3. block: => Unit 沒有輸入值,也沒有返回值 def mywhile(condition: => Boolean)(block: => Unit): Unit = { //相似while循環,遞歸 if (!condition) { block // x= 9 ,x = 8 x =7 .... mywhile(condition)(block) } } mywhile(x == 0) { x -= 1 println("x=" + x) } } }