Scala--高階函數


一、作為值的函數

  import scala.math._

  val num  = 3.14
  val func = ceil _ // _意味着確實指的是這個函數,而不是忘記了傳參數 ,func是一個函數變量,內容保存的是個函數

  val v = func(num)
  println(v)
  val arr = Array(1.0,3.14,4).map(func)  //將函數func傳遞給map方法,將他應用到數組中的所有值,然后返回結果數組
  for(i<- arr) print(i+" ")

結果:

4.0
1.0 4.0 4.0 

 

二、匿名函數

  val func = (x:Double) => x*3 //匿名函數
 val arr1 = Array(2.0,4,6).map((x:Double)=> x*3) //匿名函數 val arr2 = Array(2.0,4,6).map{(x:Double)=> x*3} //匿名函數,可以將函數用{}括起來 val arr3 = Array(2.0,4,6) map{(x:Double)=> x*3} //匿名函數,中置表示法,可以不用句號 for(i <- arr1) print(i+" ")

 

三、帶函數參數的函數

  import scala.math._
  def valueAtFunc(f: (Double) => Double) = { // f: (Double) => Double 定義函數參數為 double,返回值為double
    f(0.25) //調用函數的參數為 2.0
  }

  println(valueAtFunc(ceil _))  //將函數傳遞個 函數valueAtFunc
  println(valueAtFunc(sqrt _))

結果:

1.0
0.5

 

四、參數(類型)推斷

  import scala.math._
    def valueAtFunc(f: (Double) => Double) = { // f: (Double) => Double 定義函數參數為 double,返回值為double
      f(0.25) //調用函數的參數為 2.0
    }

    println(valueAtFunc(ceil _))  //將函數傳遞個 函數valueAtFunc
    println(valueAtFunc(sqrt _))

  valueAtFunc((x:Double) => x*3 ) //匿名函數,指定類型
  valueAtFunc((x)=>x*3)      //匿名函數,已知參數類型
  valueAtFunc(x=>x*3)        //匿名函數,已知參數類型,去掉括號
  valueAtFunc(_*3)           //使用_替換 x

  val f1 = 3 * _   //錯誤,沒指定類型
  val f2 = 3 *(_:Double)  //ok
  val f3:(Double)=>Double = 3 * _ // ok 指定了f3類型

匿名函數簡寫:

valueAtFunc((x:Double) => x*3 ) //匿名函數,指定類型
valueAtFunc((x)=>x*3) //匿名函數,已知參數類型
valueAtFunc(x=>x*3) //匿名函數,已知參數類型,去掉括號
valueAtFunc(_*3) //使用_替換 x

 

五、一些有用的高階函數

map這個方法將一個函數應用到某個集合的所有元素並返回結果

foreach將函數應用到每個元素,並不返回結果

(0 to 9).map("*" * _).foreach(println(_))

結果:

*
**
***
****
*****
******
*******
********
*********

filter輸出所有匹配某個特定條件的元素

(0 to 9).filter(_ % 2 == 0).foreach(println(_))

結果:

0
2
4
6
8

reduceLeft方法接收一個二元函數,從左到右遍歷元素

println((0 to 9).reduceLeft(_ + _))   // 相當於  (...((((0+1) + 2) + 3) + 4) ...+ 9)

結果

45

sortWith方法二元排序

"I am a bad guy".split(" ").sortWith(_.length<_.length).foreach(println(_))

結果:

I
a
am
bad
guy

 

六、閉包

閉包由代碼和代碼用到的非局部變量定義構成

 

七、SAM轉換

Single Abstract Method

 

 

八、柯里化

Currying,指的是將原本接收兩個參數的函數變成新的接收一個參數的函數的過程。

  def mul(x:Int, y:Int) = x * y  //接收兩個參數的函數

  def mulOneAtATime(x:Int) = (y:Int)=> x * y  //接收一個參數的函數,需要接收兩次參數
  def mulOneAtATime1(x:Int)(y:Int) = x * y //柯里化 簡寫
  println(mulOneAtATime(3)(4))
  println(mulOneAtATime1(3)(4))

 

柯里化用途:

傳遞一個參數調用函數,有助於對參數類型進行推斷,即類型推斷

  val a = Array("Hello","World")
  val b = Array("hello","world")

  a.corresponds(b)(_.equalsIgnoreCase(_))

Scaladoc說明

that是String類型的序列,所以第二個函數參數是(String, String) => Boolean,所以適用函數_.equalsIgnoreCase(_)傳遞兩個String類型參數的函數。

 

九、控制抽象

實現類似while條件控制,柯里化實現

  //until函數  類似於while
  def until(condition: => Boolean) (block: => Unit) { //不帶參數,沒有返回值的函數 block: => Unit
    if(condition){
      block
      until(condition)(block)
    }
  }

  var x:Int = 10
  until(x > 0){ //傳遞兩個函數體, 第一個函數體當做條件,第二個函數體當做計算塊
    x -= 1
    println(x)
  }

結果:

9
8
7
6
5
4
3
2
1
0

 

十、return表達式

  //until函數  類似於while
  def until(condition: => Boolean) (block: => Unit) { //不帶參數,沒有返回值的函數 block: => Unit
    if(condition){
      block
      until(condition)(block)
    }
  }

  var x:Int = 10
  until(x > 0){ //傳遞兩個函數體, 第一個函數體當做條件,第二個函數體當做計算塊
    x -= 1
    println(x)
  }

  def indexOf(str: String, ch:Char): Int ={
    var i = 0
    until( i!=str.length){
      if( str(i) == ch) return i      //return 返回給帶名函數,並不返回給匿名函數 {if(str(i) == ch) return i; i+=1}的until
      i+=1
    }
    return -1
  }
  println(indexOf("Hello", 'i'))

return在控制抽象中很有用。

 

 

參考《快學Scala》

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM