跳至內容

匿名函式

出自Taiwan Tongues 台語維基
這是此頁批准,以及是最近的修訂。

匿名函式(英語:Anonymous Function)佇咧電腦編程中是講一類無需定義識別碼(函式名)的函式抑是子程式,普遍存在佇咧濟種程式語言內底。

一九五八年 LISP 首先採用匿名函式,自此了後,愈來愈濟程式語言陸續採用,主流的程式語言如何 PHP 和 C + + 也陸續採用。

用途

排序

阮試看覓這个名稱排序:

寫真濟 ` 十曉零 ` 的類名是「` float `」,` 十 ` 的類名是「` int `」而且 `'十'` 的類名是「` str `」,排列了後的順序為「` float `」「` int `」,接咧是「` str `」。

該範例中的匿名函式就是 lambda 表達式:

該無名函式接受兩个變數 ` x ` 和 ` y `,通過內部函式 ` cmp ( ) ` 倒轉來兩个人的較值,下跤的例將會照長度為字串列表排序:

語言列表

範例

Python

Python 用 lambda 語法定義匿名函式,干焦需用表達式無需聲明

JavaScript

JavaScript 支援匿名函式。

小書籤嘛定咧使用這款的結構,譬如講下跤的一个小冊籤就共當前網頁的標題顯示其實 URL:

毋過,因為這个語句倒轉來值得(即 URL 本身), 足濟瀏覽器會同齊建立一个新的頁面顯示這个值。

取取代之,下跤的無頭人函式就會當做到無愛倒轉任何值:

第一對圓括號中的函式(「 ( function ( ) { document . title=location . href ; } )」)用作聲明一个崁名函式,若尾溜一對圓括號則用來執行這个函式。仝等的用法有:

PHP

PHP 四配零 . 一進前不支援匿名函式。

四配零 . 一至五孵三

PHP 四配零 . 一新加了 ` create _ function ` 函式,這是掩名函式的形初初。該函式會當建立一个隨機號名的新函式並用字串形式轉去新函式的函式名。

愛注意的是,新函式本身佮其變數攏愛囥佇咧單引號內底,若欲囥佇雙引號之內,美元符號「$」著愛轉碼變做「\ $」。

五孵三

PHP 五鋪三新增加了 ` Closure ` 類,以及能使類別的實例會當呼叫的「魔術方法」` _ _ invoke ( ) `。Lambda 函式的攏是編譯器的一種「出頭」,伊會當產生新的會當予人咻叫的 ` Closure ` 實例,袂輸函式會當予人呼叫仝款。

咧講例內底的 ` $ func ` 是 ` Closure ` 類的一个實例,而且 ` echo $ func ( ) ` 是相當的 ` $ func-> _ _ invoke ( $ z ) `。PHP 五鋪三模仿使用匿名函式,但並非支援真匿名函式,因為乎 PHP 的函式猶是第一類函式。

雖然 PHP 五配三支援閉包,但是猶需要像按呢明確標識其變數:

` $ func ` 參照了變數 ` $ x `(& $ x), 咧呼叫的時陣就會修改原來的 $ x,其結果咧函式以外嘛是會當看著的。

C + +

C + + 三分之九十八

C + + 三分之九十八標準並無原生支援匿名函式。不過會當利用 Boost 庫的 Boost . Lambda 來實現一个匿名函式。

C + + 十一

C + + 十一標準提供了匿名函式的支援,佇咧《ISO / IEC 一爿四千八百八十二 : 二千空一十一》(C + + 十一標準文件)中叫做lambda 表達式。一个 lambda 表達式有這款形式:

必須用方括號括起來的 capture 列表來開始一个 lambda 表達式的定義。

lambda 函式這个形參表比普通函式這个形參表加三條限制:

一 . 參數袂使有預設值二 . 袂當有可變長參數列三 . 袂使有無名參數若是 lambda 函式無形參而且無 mutable、exception 抑是 attribute 聲明,遐爾參數的空圓括號會當省略。毋過若需要出 mutable、exception 抑是 attribute 聲明,遐爾仔參數就算是空,圓括號嘛袂使省略。

若函式的體干焦一个 return 語句,抑是倒轉去值類型做 void,遐爾倒轉值類型聲明會當予人省略:

一个 lambda 函式的比論講下:

佇頂懸的第一个例當中這个無名函式的回值是 ` decltype ( x + y ) `。若是 lambda 函式體的形式是 ` return _ expression _ `,抑是講啥無倒轉來,抑是所有轉來語句用 ` decltype ` 攏會當檢測著仝一類型,按呢倒轉去值類型會當予人省略。

倒轉值類型會當顯式指定,如下所示:

佇這个例中,一个臨時變數,` z `,被建立來儲存中央過程。佮一般的函式仝款,中央值咧調用的前後並無存在。啥物也無倒轉來的 lambda 表達式無需顯式指定返回值,無必要寫 `-> void ` 代碼。

lambda 函式會當揣 lambda 函式的外具有 automatic storage duration 的變數,即函式的局部變數佮函式形參變數。因而,具有 static storage duration 的變數袂當被 lambda 揣取,干焦會當直接使用,這包括靜態局的變數。函式體佮遮的變數的集合起來共號做閉包。這外部變數咧聲明 lambda 表達式的時陣列佇咧方括號 ` [` 和 `] ` 中。空的方括號表示無外界變數被 capture 或者按照預設方式揣取外界變數。遮的變數被傳值掠著抑是參照掠著。著於傳值揣揣的變數,預設做唯讀(這是因為 lambda 表達式生成的為一个函式物件,伊的 ` operator ( ) ` 成員預設有 const 屬性)。 修改遮的傳值掠著變數共致使編譯報毋著。猶毋過佇 lambda 表達式的參數列的圓括號後壁使用 mutable 關鍵字,就允准 lambda 函式內面的語句修改傳值掠著變數,這寡修改佮喔 lambda 表達式(實際上是用函式的物件實現)有仝款的性命期,但無影響被傳值揣出的外部變數的值。lambda 函式會當直接使用具有 static 儲存期的變數。若佇咧 lambda 函式的揣列表中予出了 static 儲存期的變數,編譯的時陣會予出警告,猶原照起來 lambda 函式直接使用遮的外部變數來處理。所以有 static 儲存期的變數著算被聲明為傳值揣,修改該變數實際上直接修改了遮的外部變數。編譯器生成 lambda 函式對應的函式物件的時陣,袂用函式的物件的資料成員來保持予「揣取」的 static 儲存期的變數。範例:

下跤這个例展示矣 lambda 表達式的使用:

類的非靜態成員函式內底定義的 lambda 表達式會使顯式抑是隱式掠 ` this ` 指標,對而且會當參照所佇類物件的資料成員佮函式成員。物件的 this 指標必須顯式揣聲明。所以,被揣取的類的資料成員總是用 this 指標來存取,若是 this 所指的物件無存在,著 this 是空懸的指標。解決辦法是其實佇定義 lambda 進前用局部變數複製一份資料成員的值,然後揣這个局部變數的值。

lambda 函式的函式裡,會當存取下述的變數:

  • 函式參數
  • 隨部聲明的變數
  • 類資料的成員:要求 lambda 表達式聲明在類別成員函式當中,物件的 this 指標必須顯式揣聲明。
  • 有靜態儲存期的變數(如全域變數)。 一般情形下,lambda 是用來揣局部變數的,如果用其來揣全域變數抑是靜態變數,遐爾仔編譯器會報 warning
  • 被揣取的外部變數
  • 顯式揣取的變數
  • 隱式揣取的變數,使用預設揣模式(傳值抑是參照)來儉取。

lambda 函式的資料類型是函式物件,儉的時陣著愛用 ` std : : function ` 模板類型抑是 ` auto ` 關鍵字。 比如講:

一个 lambda 函式的捕捉表達式做空,則會當用普通函式指標儲存抑是呼叫。比如講:

C + + 十四

C + + 十一中揣機制的局限一 . lambda 揣著的是局部變數抑是參,不管是按值抑是按參照揣取,遮的攏是具名的左值物件。正佇咧物件是無頭路,無法度被揣取。 二 . 按值揣時間,左值是去予人複製去包中的。若準被揣取的物件是一个只移動類型的物件時陣,無法度去予人複製,就會脫箠矣。 三 . 若是被揣的物件若是一个占用的記憶體較大的物件的時陣,按值揣出顯然效率真低。

C + + 十四增加了廣義揣 ( Generalized capture ),抑是稱「初初化揣」。 著佇咧揣子句(capture clause)中增加並初開始化新的變數,該變數無需要佇咧 lambda 表達式的閉包域(enclosing scope)中存在;就算佇閉包域內底存在也會予新變數崁去 ( override )。新變數類型由伊的初始化表達式推導。也就是講乎會當建立新的變數並佇咧揣子句中著其進行初始化。這種方式稱為帶有初始化程式的揣取或者廣義 lambda 揣取。一个用途是會當對閉包域中提干焦供移動的變數並使用伊。形如講 [mVar 一=localVar 一 , mVar 二=std : : move ( localVar 二 )] ( ) { } ;

C + + 十四凡勢 lambda 函式這个形參使用 ` auto ` 關鍵字做其他的型,這實質上是函式物件的 ` operator ( ) ` 成員作為模板函式;並且允准會當變參數模板。

Visual Basic . NET

匿名函式抑是 lambda 表達式即無名的函式抑是過程,作為表達式的值。會當寫為一行抑是多行。比如講:

會當佇聲明無名函式的同時呼叫伊。單行的 lambda 表達式袂當用 Return 關鍵字,其返回類型是自動推導會出;其參數欲愛啥物攏是用 As 關鍵字指明類型,欲按怎全部是自動推捒出類型。

lambda 表達式佇定義的時陣會當使用所在上下文(context,即 C + + 語言的閉包 closure)的局部變數、參數、屬性、Me 等等的值,就算 lambda 表達式離開了定義的時陣所在 context,遮的被使用的局部變數等的值猶原有效。這是因為 lambda 表達式佇定義的時共所用著的 context 的值儲存到伊家己的定義類中。lambda 表達式會當岫狀定義。

參考資料

外部連結

  • 《深入理解 PHP 核心》第四章函式的實現第四節匿名函式佮閉包