• Lambda 表达式 Lambda Expressions (Visual Basic)


    Lambda 表达式 Lambda Expressions (Visual Basic)

    Lambda 表达式是一个不带名字的函数(function)或子过程(sub),可以用在任何接收委托的地方。Lambda 表达式可以是函数,也可以是子过程,可以是单行的,也可以写成多行。您可以把当前范围的值传递给 lambda 表达式。

    注意,RemoveHandler 语句是一个例外,您不可以给委托参数传入一个 lambda 表达式

    您使用 Function 或 Sub 关键字创建 lambda 表达式,就像创建普通函数和子过程一样。不过,lambda 表达式包含在一个语句中。

    下面例子是一个 lambda 表达式,将参数自增 1 后返回。此例子展示单行和多行的 function 式 lambda 表达式语法

    Dim increment1 = Function(x) x + 1
    Dim increment2 = Function(x)
    Return x 
    + 2
    End Function
     
    ' Write the value 2.
    Console.WriteLine(increment1(1))
     
    ' Write the value 4.
    Console.WriteLine(increment2(2))

    下面例子是一个 lambda 表达式,演示子过程的单行和多行 lambda 表达式语法,把值写到控制台。

    Dim writeline1 = Sub(x) Console.WriteLine(x)
    Dim writeline2 = Sub(x)
    Console.WriteLine(x)
    End Sub
     
    ' Write "Hello".
    writeline1("Hello")
     
    ' Write "World"
    writeline2("World")

    注意到前面的例子中,lambda 表达式赋值给了变量。当您引用该变量时,就调用该 lambda 表达式。您还可以声明 lambda 表达式的同时调用它,看下面的例子。

    Console.WriteLine((Function(num As Integer) num + 1)(5))
    lambda 表达式可以作为函数的返回值(例子在本文后面的 上下文章节 中),或者作为实参传送给委托类型的参数,像下面列子一样。
    Module Module2
     
    Sub Main()
    ' 下面代码会打印 Success, 因为 4 是偶数.
    testResult(4Function(num) num Mod 2 = 0)
     
    ' 下面代码会打印 Failure, 因为 5 不大于 10.
    testResult(5Function(num) num > 10)
    End Sub
     
    ' Sub testResult 接收两个参数,一个 integer 和一个 function 委托,该委托接收 integer 值返回 boolean 值。
    '
     如果函数接收 integer 的实参并返回 True,则输出 Success,否则输出 Failure。
     
    Sub testResult(ByVal value As Integer, ByVal fun As Func(Of IntegerBoolean))
    If fun(value) Then
    Console.WriteLine(
    "Success")
    Else
    Console.WriteLine(
    "Failure")
    End If
    End Sub
     
    End Module

    Lambda 表达式语法

    Lambda 的语法类似于标准的函数或子过程,区别如下:

    • Lambda 表达式没有名字
    • Lambda 表达式没有修饰符(modifier),如 Overloads 或 Overrides
    • 单行 lambda 函数的返回值类型不使用 As 子句标识,而是从 lambda 表达式主体计算所得值中推断。例如,lambda 表达式的主体是 cust.City = "London",则其返回值类型是 Boolean。
    • 多行 lambda 函数,可以使用 As 子句标识返回类型,或者省略掉 As 子句而自动推断返回类型。当多行 lambda 函数省略掉 As 子句,返回值的类型推断为所有 Return 子句的主导类型。主导类型是数组文本中所有其它类型可以扩大到的唯一类型。如果这个唯一类型不能决定,则主导类型是 Object。例如,返回值列表提供给数组文本包含的值类型有 Integer、Long、Double,则最终数组是 Double 类型。Integer 和 Long 扩大为 Double,且唯一是 Double。这样,Double 就是主导类型。查看详细,请看 Widening and Narrowing Conversions。
    • 单行函数的主体必须是一个有返回值的表达式,而不是一个语句。单行函数没有 Return 语句,其返回值是函数体中表达式的值。
    • 单行子过程的主体必须是一个单行语句。
    • 单行函数或子过程没有 End Function 或 End Sub 语句。
    • 您可以用 As 关键字标识 lambda 表达式参数的类型,或者自动推断该类型。要么所有参数类型都标识,要是所有都自动推断。
    • Optional 和 Paramarray 参数不被允许
    • 泛型参数不被允许

     

    上下文

    lambda 表达式跟定义它的上下文共享作用范围。它跟容纳范围(containing scope)的内部的其它代码有相同的访问权限,包括访问成员变量、函数或子过程、Me、参数、和本地变量。

    访问容纳范围(containing scope)的本地变量和参数可以超出该范围的生命期。只要委托引用的 lambda 表达式不被垃圾收集器收集,就可以访问保持的原始环境的变量。在下面的例子中,变量 target 是 makeTheGame 的本地变量,lambda 表达式 playTheGame 定义在 makeTheGame 中。注意到作为返回值的 lambda 表达式,在 Main子过程中赋值给 takeAGuess,仍然可以访问本地变量 target。

    Module Module6
     
    Sub Main()
    '变量 takeAGuess 是一个 Boolean 函数,它存储在 makeTheGame 中设置的目标数字
    Dim takeAGuess As gameDelegate = makeTheGame()
     
    ' 设置循环来玩游戏
    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"))
    ' 输入 0 表示退出游戏
    If guess = 0 Then
    gameOver 
    = True
    Else
        
    ' 测试您的猜测,并告知您是否正确。takeAGuess 方法因不同的猜测值而被多次调用
        ' Main 过程访问不了目标值,且它没有被传入。
    gameOver = takeAGuess(guess)
    Console.WriteLine(
    "Guess of " & guess & " is " & gameOver)
    End If
    End While
     
    End Sub
     
    Delegate 
    Function gameDelegate(ByVal aGuess As IntegerAs Boolean
     
    Public Function makeTheGame() As gameDelegate
     
    ' 生成目标数字,介于 1 和 10。注意到 target 是一个本地变量,
    '
     当从 makeTheGame 返回后,它就不能被直接访问了。
    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)
     
        
    ' 本游戏返回 lambda 表达式,该 lambda 表达式承载了创建它的上下文的环境,
        ' 这个环境包含 target 变量(target number)。注意到仅有当前猜测(current guess)
        ' 才是返回 lambda 表达式的参数,而不是 target。
     
    ' 猜测值跟目标值是否匹配
    Dim playTheGame = Function(guess As Integer) guess = target
     
    Return playTheGame
     
    End Function
     
    End Module

    下面例子演示嵌套 lambda 表达式的大范围访问权。当作为返回值的 lambda 表达式在 Main 中被调用(aDel),它访问这些元素。

    • 定义它的类的字段:aField
    • 定义它的类的属性:aProp
    • 定义它的方法 functionWithNestedLambda 的参数: level1
    • functionWithNestedLambda 的本地变量:lovalVar
    • 外部 lambda 表达式的参数:level2
    Module Module3
     
    Sub Main()
     
        
    ' 创建类的一个实例,属性值 Prop 设为 1
        Dim lambdaScopeDemoInstance =
            
    New LambdaScopeDemoClass With {.Prop = 1}
     
        
    ' 变量 aDel 被绑定到 functionWithNestedLambda 返回的嵌套的 lambda 表达式
        Dim aDel As aDelegate =
            lambdaScopeDemoInstance.functionWithNestedLambda(
    2)
     
        
    ' 现在返回的嵌套的 lambda 表达式被调用,4 变成参数 level3 的值
        Console.WriteLine("First value returned by aDel: " & aDel(4))
     
        
    ' 改变某些值,以验证 lambda 表达式是否可访问变量,不仅他们的原始值
        lambdaScopeDemoInstance.aField = 20
        lambdaScopeDemoInstance.Prop 
    = 30
        Console.WriteLine(
    "Second value returned by aDel: " & aDel(40))
    End Sub
     
    Delegate 
    Function aDelegate(
        ByVal delParameter 
    As IntegerAs 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 IntegerAs aDelegate
     
            
    Dim localVar As Integer = 5
     
            
    ' 当嵌套的 lambda 表达式作为 Main 的 aDel 第一次运行,变量有这些值:
            ' level1 = 2
            ' level2 = 3, Return 语句中,调用 aLambda 后
            ' level3 = 4, aDel 在 Main 中调用后
            ' locarVar = 5
            ' aField = 6
            ' aProp = 1
            ' 第二次执行, 更改了两个变量:
            ' aField = 20
            ' aProp = 30
            ' level3 = 40
            Dim aLambda = Function(level2 As Integer) _
                
    Function(level3 As Integer) _
                    level1 
    + level2 + level3 + localVar + aField + aProp
            

             
    '函数返回嵌套的 lambda,3 作为参数 level2 的值
            Return aLambda(3)
        
    End Function
     
    End Class
    End Module

    转换到委托类型

    一个 lambda 表达式可以隐式地转换为兼容的委托类型。有关兼容性的普遍问题(general requirements for compatibility),请看 Relaxed Delegate Conversion。例如,下面代码展示一个 lambda 表达式隐式转换为匹配的委托签名 Func(Of Integer, Boolean)。

    ' 明确地声明一个委托
    Delegate Function MultipleOfTen(ByVal num As IntegerAs Boolean
     
    ' 这个函数匹配委托
    Function IsMultipleOfTen(ByVal num As IntegerAs Boolean
        Return num 
    Mod 10 = 0
    End Function
     
    ' 这个方法接收一个委托类型的输入参数,checkDelegate 参数也可以是类型 Func(Of Integer, Boolean)
    Sub CheckForMultipleOfTen(ByVal values As Integer(),
            ByRef checkDelegate 
    As MultipleOfTen)
        
    For Each value In values
            
    If checkDelegate(value) Then
                Console.WriteLine(value 
    & " is a multiple of ten.")
            
    Else
                Console.WriteLine(value 
    & " is not a multiple of ten.")
            
    End If
        
    Next
    End Sub
     
     
    ' 这个方法演示显式地定义的委托(explicitly defined delegate)和 lambda 表达式传给同样的输入参数。
    Sub CheckValues()
        
    Dim values = {510112040301003}
        CheckForMultipleOfTen(values, AddressOf IsMultipleOfTen)
        CheckForMultipleOfTen(values, 
    Function(num) num Mod 10 = 0)
    End Sub

    下面代码演示 lambda 表达式隐式地转换为匹配的委托签名 Sub(Of Double, String, Double)。

    Module Module1
        Delegate 
    Sub StoreCalculation(ByVal value As Double,
            ByVal calcType 
    As String,
            ByVal result 
    As Double)
     
        
    Sub Main()
            
    ' 创建 DataTable 存储信息
            Dim valuesTable = New DataTable("Calculations")
            valuesTable.Columns.Add(
    "Value", GetType(Double))
            valuesTable.Columns.Add(
    "Calculation", GetType(String))
            valuesTable.Columns.Add(
    "Result", GetType(Double))
     
            
    ' 定义 lambda 子过程写信息到 DataTable.
            Dim writeToValuesTable = Sub(value As Double, calcType As String, result As Double)
                
    Dim row = valuesTable.NewRow()
                row(
    0= value
                row(
    1= calcType
                row(
    2= result
                valuesTable.Rows.Add(row)
            
    End Sub
     
            
    ' 定义原值
            Dim s = {123456789}
     
            
    ' 执行计算
            Array.ForEach(s, Sub(c) CalculateSquare(c, writeToValuesTable))
            
    Array.ForEach(s, Sub(c) CalculateSquareRoot(c, writeToValuesTable))
     
            
    ' 显示数据
            Console.WriteLine("Value" & vbTab & "Calculation" & vbTab & "Result")
            
    For Each row As DataRow In valuesTable.Rows
                Console.WriteLine(row(
    0).ToString() & vbTab &
                row(
    1).ToString() & vbTab &
                row(
    2).ToString())
            
    Next
     
        
    End Sub
     
     
        
    Sub CalculateSquare(ByVal number As Double, ByVal writeTo As StoreCalculation)
            writeTo(number, 
    "Square ", number ^ 2)
        
    End Sub
     
        
    Sub CalculateSquareRoot(ByVal number As Double, ByVal writeTo As StoreCalculation)
            writeTo(number, 
    "Square Root", Math.Sqrt(number))
        
    End Sub
    End Module

      

    当您将 lambda 表达式赋值给委托或者将它们作为实参传给过程时,您可以标识参数名称,但省略他们的数据类型,让类型从委托中取。

     

    例子

    下面例子定义一个 lambda 表达式,如果 nullable 参数被赋值则返回 True,否则返回 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() = {0123456789}
    Dim lastIndex =
        
    Function(intArray() As Integer) intArray.Length - 1
    For i = 0 To lastIndex(numbers)
    numbers(i) 
    += 1
    Next

    原文:http://msdn.microsoft.com/en-us/library/bb531253(v=VS.100).aspx

  • 相关阅读:
    Stereo Matching文献笔记之(一):《Cross-Scale Cost Aggregation for Stereo Matching》读后感~
    机器视觉之 ICP算法和RANSAC算法
    基于语义约束与 Graph Cuts 的稠密三维场景 重建
    RANSAC算法详解
    三维重建技术在无人机方面的应用如何?三维重建未来的学术前景如何?
    尺度空间(Scale space)理论
    网速调控、带宽限制原理探究
    Cisco交换机IOS升级
    Nmap
    vi实用命令集
  • 原文地址:https://www.cnblogs.com/feixian49/p/1739710.html
Copyright © 2020-2023  润新知