Lambda 運算式
更新:2007 年 11 月
「Lambda 運算式」(Lambda Expression) 是沒有名稱的函式,會計算並傳回單一值。委派型別 (Delegate Type) 有效時,即可使用 Lambda 運算式。
![]() |
---|
RemoveHandler 陳述式 (Statement) 是例外狀況 (Exception)。您無法針對 RemoveHandler 的委派參數傳遞 Lambda 運算式。 |
下列範例是會遞增其引數並傳回值的 Lambda 運算式。
Function (num As Integer) num + 1
因為 Lambda 運算式是運算式,所以只能做為陳述式的一部分。
例如,特別是在要多次使用函式的情況下,您可能會將函式指派至變數名稱。
Dim add1 = Function(num As Integer) num + 1
若要呼叫函式,請傳送參數的值。
' The following line prints 6.
Console.WriteLine(add1(5))
或者,您可以同時宣告並執行函式。
Console.WriteLine((Function(num As Integer) num + 1)(5))
Lambda 運算式可以傳回做為函式呼叫 (Function Call) 的值 (請見本主題稍後「內容」章節中的範例),或傳遞做為委派參數的引數。在下列範例中,布林 (Boolean) Lambda 運算式會做為引數傳遞至方法 testResult。這個方法會將布林測試套用至整數引數 value,而且當套用至 value 時,如果 Lambda 運算式傳回 True,則顯示「成功」(Success),如果 Lambda 運算式傳回 False,則顯示「失敗」(Failure)。
Module Module2
Sub Main()
' The following line will print Success, because 4 is even.
testResult(4, Function(num) num Mod 2 = 0)
' The following line will print Failure, because 5 is not > 10.
testResult(5, Function(num) num > 10)
End Sub
' Sub testResult takes two arguments, an integer value and a
' Boolean function.
' If the function returns True for the integer argument, Success
' is displayed.
' If the function returns False for the integer argument, Failure
' is displayed.
Sub testResult(ByVal value As Integer, ByVal fun As Func(Of Integer, Boolean))
If fun(value) Then
Console.WriteLine("Success")
Else
Console.WriteLine("Failure")
End If
End Sub
End Module
查詢中的 Lambda 運算式
在 Language-Integrated Query (LINQ) 中,Lambda 運算式是許多標準查詢運算子的基礎。編譯器 (Compiler) 會建立 Lambda 運算式以擷取基本查詢方法 (例如 Where、Select、Order By、Take While 等等) 中定義的計算。
例如,以下列查詢為例:
Dim londonCusts = From cust In db.Customers
Where cust.City = "London"
Select cust
這個範例會編譯成下列程式碼:
Dim londonCusts = db.Customers _
.Where(Function(cust) cust.City = "London") _
.Select(Function(cust) cust)
如需查詢方法的詳細資訊,請參閱查詢 (Visual Basic)。
Lambda 運算式語法
Lambda 運算式的語法類似標準函式。其差異如下:
Lambda 運算式沒有名稱。
Lambda 運算式不能有修飾詞 (Modifier),例如 Overloads 或 Overrides。
Lambda 運算式不會使用 As 子句指定函式的傳回型別。而是從 Lambda 運算式評估之主體的值來推斷型別。例如,如果 Lambda 運算式的主體是 Where cust.City = "London",其傳回型別為 Boolean。
函式的主體必須是運算式,而不是陳述式。主體可以由對函式程序的呼叫組成,但不可由對子程序的呼叫組成。
沒有 Return 陳述式。函式傳回的值就是函式主體中運算式的值。
沒有 End Function 陳述式。
所有參數都必須具有指定的資料型別,不然所有參數就都必須經過推斷。
不允許使用 Optional 和 Paramarray 參數。
不允許使用泛型參數。
因為這些限制以及 Lambda 運算式的使用方式,所產生的結果通常都是簡短不複雜的。
內容
任一 Lambda 運算式定義於某個方法中時,該運算式會將本身的內容與該方法共用。它的存取權限與包含方法中撰寫的任何程式碼相同。這包括對包含方法中成員變數、函式和子函式、Me 及參數和本機變數的存取權。
對於包含方法中的本機變數和參數的存取權期,可以延伸超過該方法的存留期 (Lifetime)。只要委派 (Delegate) 參考無法進行記憶體回收的 Lambda 運算式,就會保留對於原始環境中變數的存取權。在下列範例中,變數 target 是 makeTheGame 的本機變數,而後者是 Lambda 運算式 playTheGame 在其中定義的方法。請注意,在 Main 中指派給 takeAGuess 的傳回 Lambda 運算式,仍然可以存取本機變數 target。
Module Module1
Sub Main()
' Variable takeAGuess is a Boolean function. It stores the target
' number that is set in makeTheGame.
Dim takeAGuess As gameDelegate = makeTheGame()
' Set up the loop to play the game.
Dim guess As Integer
Dim gameOver = False
While Not gameOver
guess = CInt(InputBox("Enter a number between 1 and 10 (0 to quit)", "Guessing Game", "0"))
' A guess of 0 means you want to give up.
If guess = 0 Then
gameOver = True
Else
' Tests your guess and announces whether you are correct. Method takeAGuess
' is called multiple times with different guesses. The target value is not
' accessible from Main and is not passed in.
gameOver = takeAGuess(guess)
Console.WriteLine("Guess of " & guess & " is " & gameOver)
End If
End While
End Sub
Delegate Function gameDelegate(ByVal aGuess As Integer) As Boolean
Public Function makeTheGame() As gameDelegate
' Generate the target number, between 1 and 10. Notice that
' target is a local variable. After you return from makeTheGame,
' it is not directly accessible.
Randomize()
Dim target As Integer = CInt(Int(10 * Rnd() + 1))
' Print the answer if you want to be sure the game is not cheating
' by changing the target at each guess.
Console.WriteLine("(Peeking at the answer) The target is " & target)
' The game is returned as a lambda expression. The lambda expression
' carries with it the environment in which it was created. This
' environment includes the target number. Note that only the current
' guess is a parameter to the returned lambda expression, not the target.
' Does the guess equal the target?
Dim playTheGame = Function(guess As Integer) guess = target
Return playTheGame
End Function
End Module
下列範例示範巢狀 Lambda 運算式的廣泛存取權限。當傳回的 Lambda 運算式是從 Main 執行為 aDel 時,它會存取下列項目:
在其中進行定義的類別 (Class) 欄位:aField
在其中進行定義的類別屬性:aProp
在其中進行定義之方法 functionWithNestedLambda 的參數:level1
functionWithNestedLambda 的本機變數:localVar
形成巢狀之 Lambda 運算式的參數:level2
Module Module3
Sub Main()
' Create an instance of the class, with 1 as the value of
' the property.
Dim lambdaScopeDemoInstance = New LambdaScopeDemoClass _
With {.Prop = 1}
' Variable aDel will be bound to the nested lambda expression
' returned by the call to functionWithNestedLambda.
' The value 2 is sent in for parameter level1.
Dim aDel As aDelegate = _
lambdaScopeDemoInstance.functionWithNestedLambda(2)
' Now the returned lambda expression is called, with 4 as the
' value of parameter level3.
Console.WriteLine("First value returned by aDel: " & aDel(4))
' Change a few values to verify that the lambda expression has
' access to the variables, not just their original values.
lambdaScopeDemoInstance.aField = 20
lambdaScopeDemoInstance.Prop = 30
Console.WriteLine("Second value returned by aDel: " & aDel(40))
End Sub
Delegate Function aDelegate(ByVal delParameter As Integer) _
As Integer
Public Class LambdaScopeDemoClass
Public aField As Integer = 6
Dim aProp As Integer
Property Prop() As Integer
Get
Return aProp
End Get
Set(ByVal value As Integer)
aProp = value
End Set
End Property
Public Function functionWithNestedLambda _
(ByVal level1 As Integer) As aDelegate
Dim localVar As Integer = 5
' When the nested lambda expression is executed the first
' time, as aDel from Main, the variables have these values:
' level1 = 2
' level2 = 3, after aLambda is called in the Return statement
' level3 = 4, after aDel is called in Main
' locarVar = 5
' aField = 6
' aProp = 1
' The second time it is executed, two values have changed:
' aField = 20
' aProp = 30
' level3 = 40
Dim aLambda = Function(level2 As Integer) _
Function(level3 As Integer) _
level1 + level2 + level3 + localVar _
+ aField + aProp
' The function returns the nested lambda, with 3 as the
' value of parameter level2.
Return aLambda(3)
End Function
End Class
End Module
轉換為委派型別
Lambda 運算式可以隱含地轉換為相容的委派型別。如需一般相容性需求的詳細資訊,請參閱寬鬆委派轉換。
此外,當您將 Lambda 運算式指派為委派時,可以指定參數名稱但略過其資料型別,以便從委派採用型別。在下列範例中,Lambda 運算式會指派至型別為 ExampleDel 且名稱為 del 的變數,此委派採用兩個參數,一個為整數、一個為字串。請注意,並未指定 Lambda 運算式中參數的資料型別。但是,del 需要整數引數和字串引數,如 ExampleDel 的定義中所指定。
' Definition of function delegate ExampleDel.
Delegate Function ExampleDel(ByVal arg1 As Integer, _
ByVal arg2 As String) As Integer
' Declaration of del as an instance of ExampleDel, with no data
' type specified for the parameters, m and s.
Dim del As ExampleDel = Function(m, s) m
' Valid call to del, sending in an integer and a string.
Console.WriteLine(del(7, "up"))
' Neither of these calls is valid. Function del requires an integer
' argument and a string argument.
' Not valid.
' Console.WriteLine(del(7, 3))
' Console.WriteLine(del("abc"))
範例
下列範例定義 Lambda 運算式,在可為 Null 的引數具有指派值時傳回 True,而其值為 Nothing 時傳回 False。
Dim notNothing = Function(num? As Integer) _ num IsNot Nothing Dim arg As Integer = 14 Console.WriteLine("Does the argument have an assigned value?") Console.WriteLine(notNothing(arg))
下列範例定義 Lambda 運算式,會傳回陣列中最後一個元素的索引。
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} Dim lastIndex = Function(intArray() As Integer) _ intArray.Length - 1 For i = 0 To lastIndex(numbers) numbers(i) = numbers(i) + 1 Next
請參閱
工作
HOW TO:在 Visual Basic 中將程序傳遞至其他程序