關於C 的lambda表示式

2021-09-25 22:33:53 字數 4033 閱讀 8151

什麼是lambda表示式呢?

lambda表示式(lambda expression)是乙個匿名函式,它可以包含表示式和語句,並且可用於建立委託或表示式目錄樹型別。lambda表示式基於數學中的λ演算得名,直接對應於其中的lambda抽象(lambda abstraction),是乙個匿名函式,即沒有函式名的函式。lambda表示式可以表示閉包。

所有 lambda 表示式都使用 lambda 運算子 =>,該運算子讀為「goes to」。該 lambda 運算子的左邊是輸入引數(如果有),右邊包含表示式或語句塊。lambda 表示式 x => x * x 讀作「x goes to x times x」。可以將此表示式分配給委託型別。

lambda表示式的語法比匿名方法簡單,如果所呼叫的方法有引數,且不需要引數,匿名方法的語法就比較簡單,因為這樣不需要提供引數

class

program ;

console

.writeline(lambda(

"start of string"

)); }

} lambda運算子「=>」的左邊列出了需要的引數。lambda運算子的右邊定義了賦予lambda變數的方法的實現**。

引數lambda表示式有幾種定義引數的方式。如果只有乙個引數,只寫出引數名就足夠了。下面的lambda表示式使用了引數s。因為委託型別定義了乙個string引數,所以s的型別就是string。實現**呼叫string.format()方法來返回乙個字串,在呼叫該委託時,就把字串寫到控制台上:

func

<

string

, string

> oneparam = s =>

string

.format(

"change uppercase"

, s.toupper());

console

.writeline(oneparam(

"test"

));

如果委託使用多個引數,就把引數名放在化括號中。這裡引數x和y的型別是double,由func委託定義:

func

<

double

, double

, double

> twoparams = (x, y) => x * y;

console

.writeline(twoparams(3, 2));

為了方便,可以在花括號中給變數名新增引數型別。如果編譯器不能匹配過載後的版本,那麼使用引數型別可以幫助找到匹配的委託:

func

<

double

, double

, double

> twoparamswithtypes = (

double

x,double

y) => x * y;

console

.writeline(twoparamswithtypes(4, 2));

多行**

如果lambda表示式只有一條語句,在方法塊內就不粗要花括號和return語句,因為編譯器會新增一條隱式的return語句。

func

<

double

, double

> square = x => x * x;

新增花括號、return語句和分號完全合法的,通常這比不新增這些符號更容易閱讀:

func

<

double

, double

> square = x => ;

但是,如果在lambda表示式的實現**中需要多條語句,就必須新增花括號和return語句:

func

<

string

, string

> lambda = param => ;

通過lambda表示式可以訪問lambda表示式塊外部的變數。這稱為閉包。閉包是乙個非常好的功能,但如果使用不當,也會非常危險。

在下面的示例中,

func

<

int,

int>

型別的lambda表示式需要乙個int引數,返回乙個int。該lambda表示式的引數用變數x定義。實現**還訪問了lambda表示式外部的變數someval。只要不假設在呼叫f時,lambda表示式建立了乙個以後使用的新方法,這似乎沒有什麼問題。看看下面這個**塊,呼叫f的返回值應是x加5的結果,但似乎不是這樣:

intsomeval = 5;

func

<

int,

int> f = x => x + someval;

假定以後要修改變數someval,於是呼叫lambda表示式時,會使用someval的新值。呼叫f(3)的結果是10:

someval = 7;

console

.writeline(f(3));

特別是,通過另乙個執行緒呼叫lambda表示式時,我們可能不知道進行了這個呼叫也不知道外部變數的當前值是什麼。

現在我們也許會奇怪,如何在lambda表示式的內部訪問lambda表示式外部的變數。為了理解這一點,看看編輯器在定義lambda表示式時做了什麼。對於lambda表示式

x => x + someval

,編譯器會建立乙個匿名類,它有乙個建構函式來傳遞外部變數。該建構函式取決於從外部傳遞進來的變數個數。對於這個簡單的例子,建構函式接受乙個int。匿名類包含乙個匿名方法,其實現**、引數和返回型別由lambda表示式定義:

public

class

anonymousclass

public

intanonymousemethod(

intx)

} 使用foreach語句有乙個很大的改變。在下面的例子中,首先用值10、20、30填充乙個名為values的列表。變數funcs引用乙個泛型列表,其中每個物件都引用func型別的委託。第一條foreach語句新增了funcs列表中的每個元素。新增到項中的函式使用lambda表示式定義。該lambda表示式使用了乙個變數val,該變數在lambda表示式的外部定義為foreach語句的迴圈變數。第二條foreach語句迭代funcs列表,以呼叫列表中引用的每個函式:

varvalues =

newlist

<

int>() ;

varfuncs =

newlist

<

func

<

int>>();

foreach

(var

val

invalues)

foreach

(var

f in

funcs)

在c#5.0中,這段**的結果發生了變化。使用c#4或更早版本的編譯器時,會在控制台中輸出33次。在第乙個foreach迴圈中使用閉包時,所建立的函式是在呼叫時,而不是在迭代時獲得val變數的值。編譯器會從foreach語句建立乙個while迴圈。在c#4中,編譯器在while迴圈外部定義迴圈變數,在每次迭代中重用這個變數。因此,在迴圈結束時,該變數的值就是最後一次迭代時的值。要想在使用c#4時,讓**的結果為10、20、30,必須將**改為使用乙個區域性變數,並將這個區域性變數傳入lambda表示式。這樣,每次迭代時就將保留乙個不同的值。

varvalues =

newlist

<

int>() ;

varfuncs =

newlist

<

func

<

int>>();

foreach

(var

val

invalues)

foreach

(var

f in

funcs)

在c#5.0中,不再需要做這種**修改(即將**修改為區域性變數)。c#5.0會在while迴圈的**塊中建立乙個不停的區域性迴圈變數,所以值會自動得到保留。這是c#4.0和c#5.0的區別,必須知道這一點。

lambda表示式可用於型別為委託的任意地方。型別是expression或expression時,也可以使用lambda表示式。此時編譯器會建立乙個表示式樹。

關於Lambda表示式

lambda表示式是c 3.0的一種新語法,語法簡潔 為編寫匿名方法提供了更簡明的函式式的句法.我通過乙個示例來說明lambda表示式的原理 lambda表示式和匿名方法都 於委託 我們來看看委託的使用 在c 1.0時 c 2.0時可以使用匿名方法 c 3.0使用lambda表示式 使用lambda...

關於lambda表示式

lambda函式也叫做匿名函式,就是說沒有具體名稱的函式。lambda只是乙個表示式,一般用來定義簡單的函式,不能共享給別的程式呼叫。lambda函式可以使用任何數量的引數,但只能有乙個表示式。會返回乙個函式物件,但這個物件不會賦給乙個識別符號。lambda函式可以在需要函式物件的任何地方使用。用法...

lambda表示式 lambda表示式

1.概述 c 11 中的 lambda 表示式用於定義並建立匿名的函式物件,以簡化程式設計工作。lambda 的語法形式如下 函式物件引數 操作符過載函式引數 mutable 或 exception 宣告 返回值型別可以看到,lambda 主要分為五個部分 函式物件引數 操作符過載函式引數 muta...