1. 程式人生 > >Scala教程(十)函式與閉包詳解

Scala教程(十)函式與閉包詳解


Scala教程()函式與閉包詳解

1 函式

1.1 本地函式

函數語言程式設計風格的一個重要設計原則:程式應該被解構成若干小的函式,每個完成一個定義良好的任務。單個函式經常很小。這種風格的好處是它給了程式設計師許多可以靈活組裝成更復雜事物的建造模組。每個小塊應該充分簡化到足以單獨理解。

   Scala中提供了可以把函式定義在另一個函式中。就好象本地變數那樣,這種本地函式僅在包含它的程式碼塊中可見。

  def processData(fileName:String,width:Int){
      // 本地函式
      def processLine(line:String){
          // 長度大數指定的長度,進行列印
          if(line.length() > width){
              println(fileName+":"+line)
          }
      }
      
      // 讀取檔案
      val source = Source.fromFile("E:\\input.txt");
      for(line <- source.getLines()){
          processLine(line);
      }
  }

processLine的定義放在processFile的定義裡。作為本地函式,processLine的範圍侷限於processFile之內,外部無法訪問。

1.2 函式值

函式文字被編譯進一個類,類在執行期例項化的時候是一個函式值:function value。因此函式文字和值的區別在於函式文字存在於原始碼,而函式值存在於執行期物件。

    // =>指明這個函式把左邊的東西(任何整數x)轉變成右邊的東西(x + 1)。所以,這是一個把任何整數x對映為x + 1的函式。
    var increase = (x:Int) => x+1;

    // 執行結果:11
    println(increase(10))
    
    // 因為increase是var,你可以在之後重新賦給它不同的函式值。
    increase = (x: Int) => x + 9999
    
    // 執行結果:10009
    println(increase(10));    
    
    // 所有的集合類都能用到foreach方法。
    val someNumbers = List(-11, -10, -5, 0, 5, 10)
    someNumbers.foreach((x: Int) => println(x))

    輸出結果:

         -11

         -10

         -5

         0

         5

         10

    // filter 方法選擇集合型別裡可以通過使用者提供的測試的元素。測試是通過函式的使用來提供的。例如,函式(x: Int) => x > 0可以被用作過濾。
    someNumbers.filter((x: Int) => x > 0).foreach { (x:Int) => println(x) }

    輸出結果:

        5

        10

    // 下劃線當做一個或更多引數的佔位符,只要每個引數在函式文字內僅出現一次
    someNumbers.filter(_ > 0).foreach { (x:Int) => println(x) }

    輸出結果:

        5

        10

    /*
     * _ + _將擴充套件成帶兩個引數的函式文字。
     * 這也是僅當每個引數在函式文字中最多出現一次的情況下你才能使用這種短格式的原因。
     * 多個下劃線指代多個引數,而不是單個引數的重複使用。
     * 第一個下劃線代表第一個引數,第二個下劃線代表第二個,第三個……,如此類推。
     */
    val f = (_: Int) + (_: Int)
    println(f(5, 10))

    輸出結果:15

1.3 偏應用函式

以這種方式使用下劃線時,你就正在寫一個偏應用函式:partially appliedfunction

        val data = List(1,2,3,4,5,6);
        // for簡寫遍歷List
        data.foreach(println)
        data.foreach(println _)
        data.foreach(x=>println(x))

1.4 部分應用函式

比如定義了一個函式: def sum(a:Int,b:Int,c:Int) = a + b +c,當呼叫sum的時候,如果不提供所有的引數或某些引數還未知時,比如sum _ ,sum(1,_:Int,3), 這樣就生成了所謂的部分應用函式。

部分應用函式只是邏輯上的一個表達,scala編譯器會用Function1 Function2這些類來表示它。   

        // 定義了一個函式: 
        def sum(a:Int,b:Int,c:Int) = a + b +c
        println(sum(1,2,3));
        
        /*
         *  部分應用函式(Partial Applied Function)是缺少部分引數的函式,是一個邏輯上概念偏函式是隻對函式定義域的一個子集進行定義的函式。
         * 呼叫sum的時候,如果不提供所有的引數或某些引數還未知時,比如sum _ , sum(1,_:Int,3), 這樣就生成了所謂的部分應用函式。
         * 部分應用函式只是邏輯上的一個表達,scala編譯器會用Function1, Function2這些類來表示它.
         */
        val fp_a = sum _;
        println(( sum _).apply(1,2,3));
        val fp_b = sum(1,_:Int,3)
        println(fp_b(2))
        println(fp_b(10))

1.5 高階函式例項

高階函式:函式當作引數進行傳遞。

        // 生成1到9集合,將其中的每個項都變成*,再次進行列印
        (1.to(9)).map("*" * _).foreach(println);

輸出結果:

      *

      **

      ***

      ****

      *****

      ******

      *******

      ********

      *********

        // 生成1到9集合,對2取產為0,進行列印輸出
        (1.to(9)).filter(_ % 2 == 0).foreach(println);

輸出結果:

      2

      4

      6

      8

        // 從右向左連乘 格式  (…((1 * 2) * 3) * … * 9)
        println((1.to(9)).reduceLeft(_ * _))

輸出結果:362880

     // 將內容進拆分 拆分後的單詞進行拆 
     "Spark is the most exciting thing happening in big data today"
      .split(" ").sortWith(_.length < _.length)
      .foreach(println);<span lang="EN-US" style="font-family:Consolas;color:black;font-size:12.0pt;">   </span>

輸出結果:

            is

            in

            the

            big

            most

            data

            Spark

            thing

            today

            exciting

            happening

        // 呼叫Java的方法:向上取整計算,它返回的是大於或等於函式引數,並且與之最接近的整數。
        def ceil (x:Double) :Double = java.lang.Math.ceil(x);
        val fun = ceil _;
        val num  =3.14;
        println(fun(num))
輸出結果:4.0
        // array陣列進行迴圈呼叫函式
        Array(3.14,1.42,2.0).map(fun).foreach(println);

輸出結果:  4.0

             2.0

             2.0   

        // array陣列元素 * 3
        val triple = (x:Double) => 3 * x
        Array(3.14,1.42,2.0).map{ (x : Double) => 3 * x}.foreach(println);
        Array(3.14,1.42,2.0).map(triple).foreach(println);

輸出結果:9.42

            4.26

            6.0

        /*
         *  (引數型別) => 結果型別
         *  由於high_order_functions是一個接受函式引數的函式,因此它被稱做高階函式(higher-order function)。
         */
        def high_order_functions(f:(Double) => Double) =f(0.25);
        println(high_order_functions(ceil _))

輸出結果:1.0

       /*
        *  閉包寫法
        *  mulBy函式有一個型別為Double的引數,返回一個型別為 (Double) => Double 的函式。因此,它的型別為:(Double) => ((Double) => Double)
        *  mulBy的威力在於,它可以產出能夠乘以任何數額的函式:
        */
        def mulBy(factor:Double) = (x:Double) => factor* x
        val quintuple = mulBy(5)
        println(quintuple(20))
輸出結果:100.0
        // 引數(型別)推斷
        // Scala會盡可能幫助你推斷出型別資訊。舉例來說,你不需要將程式碼寫成:
        println(high_order_functions((x:Double) => 3 * x))
        
        /*
         * 由於high_order_functions方法知道你會傳入一個型別為 
         * (Double) => Double 的函式,你可以簡單地寫成:
         */
        high_order_functions((x) => 3 * x)
        
        // 作為額外獎勵,對於只有一個引數的函式,你可以略去引數外圍的():
        high_order_functions(x => 3 * x)
        
        // 如果引數在=>右側只出現一次,你可以用_替換掉它:
        high_order_functions(3 * _)

輸出結果:0.75

        // 引數型別
        val fun2 = 3 * (_:Double)
        val fun3:(Double) => Double = 3 *
 

2 閉包

2.1 定義閉包

   add函式首次呼叫引數值為:1,該變數在(x:Int) =>  x +more函式的函式體內被引用,該值賦值a。然後引數變數more從執行時的棧上被彈出來。

接下來add函式再次被呼叫,這次引數值設定為了10,該變數在(x:Int) =>  x +more再次被引用,打印出計算結果的資訊。

      def add(more:Int) = (x:Int) =>  x +more       
      val a = add(1);
      println(a(10));
      
      val b = add(1000);
      println(b(10));

    --以上為Scala的函式與閉包詳解內容,謝謝大家對我的關注。

                                                                                                                                                                                      ——厚積薄發(yuanxw)

相關推薦

Scala教程()函式

Scala教程(十)函式與閉包詳解 1 函式 1.1 本地函式 函數語言程式設計風格的一個重要設計原則:程式應該被解構成若干小的函式,每個完成一個定義良好的任務。單個函式經常很小。這種風

python函式呼叫順序、高階函式、巢狀函式

  一:函式呼叫順序:其他高階語言類似,Python 不允許在函式未宣告之前,對其進行引用或者呼叫錯誤示範: def foo(): print 'in the foo' bar() foo() 報錯: in the foo Traceback (most re

一、Go基礎程式設計:遞迴函式函式型別、匿名函式

1. 遞迴函式 遞迴指函式可以直接或間接的呼叫自身。 遞迴函式通常有相同的結構:一個跳出條件和一個遞迴體。所謂跳出條件就是根據傳入的引數判斷是否需要停止遞迴,而遞迴體則是函式自身所做的一些處理。 //通過迴圈實現1+2+3……+100 func Test01() int { i

Scala入門到精通——第五節 函式

本節主要內容 (一)函式字面量(值函式) (二)匿名函式 (三)函式的簡化 (四)函式引數 (四)閉包 函式字面量(值函式) 函式字面量(function literal),也稱值函式(function values),指的是函式可以賦值給變數

[js點滴]js函式函式

1、匿名函式 函式是JavaScript中最靈活的一種物件,這裡只是講解其匿名函式的用途。匿名函式:就是沒有函式名的函式。 1.1 函式的定義,首先簡單介紹一下函式的定義,大致可分為三種方式 第一種:這也是最常規的一種 function dou

Scala 程式設計—第五節:函式

1.函式定義 如下,定義一個函式,用來比較兩數大小得出最大值 def max(x: Int, y: Int): Int = { if (x> y) x else y } 以上述定義的函式為例,看下scala函式的基本構成 max 函式可以簡寫為

scala程式設計-函式

3.頭等函式 3.1 object foreach_test{     val someNumbers = List(1,2,3,4,5,65)     //所有集合類都能用到的foreach方法。他以函式作為入參,並對每個元素都呼叫該函式,下面是如何用他列印輸出所有列表元

Go入門自學寶典0012-匿名函式

匿名函式與閉包 所謂閉包就是一個函式“捕獲”了和它在同一作用域的其它常量和變數。這就意味著當閉包被呼叫的時候,不管在程式什麼地方呼叫,閉包能夠使用這些常量或者變數。它不關心這些捕獲了的變數和常量是否已經超出了作用域,所以只有閉包還在使用它,這些變數就還會存在。 在Go語言裡,所有的匿名函

PHP之回撥、匿名函式

回撥函式:通俗的解釋就是把函式作為引數傳入進另一個函式中使用;PHP中有許“需求引數為函式”的函式,像array_map,usort,call_user_func_array之類,他們執行傳入的函式,然後直接將結果返回主函式。好處是函式作為值使用起來方便,而且程式碼簡潔,可讀

python3基礎教程:列舉,你需要知道的知識點

列舉   字典表示方法:{‘yellow’:1,'green':2} 型別一旦確定下來是不能被改變的 列舉的保護功能:禁止修改標籤的值 避免出現重複的標籤 更多Python視訊、原始碼、資料加群960410445免費獲取  

一個函式理解js的this和——debounce

debounce應用場景模擬 debounce函式,俗稱防抖函式,專治input、resize、scroll等頻繁操作打爆瀏覽器或其他資源。前端面試幾乎必考,當然肯定會做一些變化。 <!DOCTYPE html> <html lang="en">

javascript中的返回函式

在Javascript中沒有類的概念,函式就是第一類物件。函式就是物件,主要的表現形式有:1. 函式可以在執行時建立,也可以在執行的過程中建立。2. 函式可以被分配給其他變數,可以將它們的引用複製給其他變數。3. 函式可以作為引數傳遞給其他函式,可以作為其他函式的

JavaScript中的

bsp 參考 參數 med ica 如果 bar 描述 javascrip 閉包是JavaScript的重要特性,非常強大,可用於執行復雜的計算,可並不容易理解,尤其是對之前從事面向對象編程的人來說,對 JavaScript 認識和編程顯得更難。特別是在看一些開源的Java

Swift 中的Closures()

mount light sca ring 需要 line rem sin 代碼 Swift 中的Closures(閉包)詳解 在Swift沒有發布之前,所有人使用OC語言編寫Cocoa上的程序,而其中經常被人們討論的其中之一 -- Block 一直備受大家的喜愛。在Swif

python中

ner copy bsp div 執行 gpo 註意 outer 在一起 閉包這個概念好難理解,身邊朋友們好多都稀裏糊塗的,稀裏糊塗的林老冷希望寫下這篇文章能夠對稀裏糊塗的夥伴們有一些幫助~ 請大家跟我理解一下,如果在一個函數的內部定義了另一個函數,外部的我們叫

javascript

一、什麼是匿名函式 建立一個函式並將它賦值給變數functionName,這種情況下建立的函式,即匿名函式。(函式表示式就是匿名函式)   二、閉包 1.什麼是閉包? 閉包就是能夠讀取其他函式內部變數的函式。 只有函式內部的子函式才能讀取區域性變數,因此可以把閉包簡單理解成“定義在一個函

什麼是閉包? 內層函式引用外層函式的變數,並把這個變數封閉到它的函式體內,直到它被呼叫後才釋放,有人說,閉包是內層函式和外層函式溝通的橋樑 還是不夠明白?讓我們通過程式碼說明. def f1(): name='Lily' def inner():

JS

一.函式和作用域 自定義函式 XXX() function XXX( ) { } // 呼叫函式,放在哪個位置都可以 // 如果是獲取元素,元素必須放在上面 var fn = function () { } fn() // 必須放在宣告的後面 這種用v

js原理

雖然身為一個java程式設計師,但是覺得了解前端知識是很有必要的,js中有一個比較難的知識點--閉包,不知道大家對閉包是怎樣理解的。接下來通過一個小例子來帶大家瞭解下js中的閉包。 何為閉包:把內部函式儲存到外部一定會形成閉包 再瞭解閉包之前,得先知道函式的預編譯、作用域

JavaScript

關於閉包: ECMAScript中給閉包的定義: 閉包,指的是詞法表示包括不被計算的變數的函式,也就是說函式可以使用函式之外定義的變數。 閉包 是指有權訪問另一個函式作用域中的變數的函式,建立閉包的最常見的方式就是在一個函式內建立另一個函式,通過另一個函式訪問