Лямбда-выражения
Обновлен: Ноябрь 2007
Лямбда-выражения является функцией без имени, которая вычисляет и возвращает одиночное значение. Лямбда-выражения можно использовать везде, где допустимы типы делегата.
Примечание. |
---|
Исключением является оператор RemoveHandler. Невозможно передать лямбда-выражение в качестве параметра делегата RemoveHandler. |
В следующем примере лямбда-выражение увеличивает значение своего аргумента и возвращает его.
Function (num As Integer) num + 1
Поскольку лямбда-выражение является выражением, его можно использовать только в составе оператора.
Например, можно присвоить функцию переменной, особенно если ее значение требуется использовать несколько раз.
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))
Лямбда-выражения могут быть возвращены как значение вызванной функции (как это показано в примере в разделе "Контекст" ниже в этом разделе), или могут быть переданными в качестве аргумента в параметр делегата. В следующем примере лямбда-выражения типа Boolean передаются в качестве аргумента в метод testResult. Метод применяет логическую проверку целочисленного аргумента value и отображает сообщение об успешности (лямбда-выражение возвращает True и присваивает это значение value) или ошибке (лямбда-выражение возвращает False).
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
Лямбда-выражения в запросах
В LINQ (Language-Integrated Query) лямбда-выражения лежат в основе многих стандартных операторов запроса. Компилятор создает лямбда-выражения для записи вычислений, которые определены в основных методах запроса, таких, как 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).
Синтаксис лямбда-выражений
Синтаксис лямбда-выражения схож с синтаксисом стандартной функции. Различия заключаются в следующем:
Лямбда-выражение не имеет имени.
Лямбда-выражения не могут включать модификаторы, такие как Overloads или Overrides.
Лямбда-выражения не используют предложение As для обозначения типа возвращаемого значения функции. Вместо этого тип выводится из значения, которое вычисляется в теле лямбда-выражения. Например, если тело лямбда-выражения — Where cust.City = "London", возвращается тип Boolean.
Тело функции должно быть выражением, а не оператором. Тело может содержать вызов процедуры Function, но не вызов процедуры Sub.
Отсутствует оператор Return. Значение, возвращаемое функцией, является значением выражения в теле функции.
Отсутствует оператор End Function.
Все параметры должны иметь определенный или выводимый тип данных.
Параметры Optional и Paramarray не разрешены.
Универсальные параметры не разрешены.
В связи с указанными ограничениями и особенностями использования лямбда-выражения обычно представляют собой короткие и упрощенные выражения.
Контекст
Лямбда-выражение использует общий контекст с методом, внутри которого оно определено. Оно имеет те же права доступа что и код, содержащийся в методе. Это включает доступ к переменным членов, функциям, процедурам, Me, а также параметрам и локальным переменным в содержащем методе.
Доступ к локальным переменным и параметрам в содержащем методе можно продлить сверх времени существования этого метода. До тех пор, пока делегат, ссылающийся на делегат лямбда-выражения, недоступен сборщику мусора, доступ к переменным среды исходного кода сохраняется. В следующем примере переменная target является локальной для метода makeTheGame, в котором определено лямбда-выражение playTheGame. Обратите внимание, что возвращаемое лямбда-выражение, присваивается takeAGuess в Main, который по-прежнему сохраняет доступ к локальной переменной 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
В следующем примере показан широкий спектр прав доступа вложенных лямбда-выражений. При выполнении возвращаемого лямбда-выражения из Main как aDel, он обращается к следующим элементам:
Поле класса, в котором он определен: aField.
Свойство класса, в котором он определен: aProp.
Параметр метода functionWithNestedLambda, в котором он определен: level1.
Локальная переменная functionWithNestedLambda: localVar.
Параметр лямбда-выражения, в котором он является вложенным: 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
Преобразование к типу делегата
Лямбда-выражения могут быть неявно преобразованы к совместимому типу делегата. Дополнительные сведения об общих требованиях к совместимости см. в разделе Ослабленное преобразование делегата.
Кроме того, при присваивании лямбда-выражения делегатам можно указать имена параметров, но опустить их типы, позволяя принимать типы из делегата. В следующем примере лямбда-выражению присваивается переменная с именем del из типа делегата ExampleDel, который принимает два параметра — целого и строкового типа. Обратите внимание, что типы данных параметров в лямбда-выражении не определены. Однако 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"))
Примеры
В следующем примере определяется лямбда-выражение, которое возвращает True, если аргументу типа nullable было присвоено значение, и False, если аргумент имеет значение Nothing.
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))
В следующем примере определяется лямбда-выражение, возвращающее индекс последнего элемента в массиве.
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
См. также
Задачи
Практическое руководство. Передача процедур другой процедуре в Visual Basic
Практическое руководство. Создание лямбда-выражения
Основные понятия
Знакомство с LINQ в Visual Basic
Ослабленное преобразование делегата