• Lambda 笔记


    lambda表达式,将会带来代码的灵活性,同时使我们的代码更具表现力。
         
       Dim doubleIt As Func(Of Integer, Integer) = _
                Function(x As Integer) x * 2

    上面的这个例子,是一个基本lambda表达式定义的示例。它将 doubleIt 定义为接受一个整数并返回一个整数的 lambda 表达式。该 lambda 表达式有效地接受输入,将其乘以 2,然后返回结果。

    Func类型

    func类型实际上是一种将返回类型指定为最后一个泛型参数并允许提供最多四个参数作为前导泛型参数供应的委托(实际有若干 Func 委托,其中每个委托都接受一定数量的参数)。在 System 命名空间的程序集 System.Core.dll 中定义了 Func 的委托类型。

            Dim f0 As Func(Of Boolean)
            Dim f1 As Func(Of Integer, Boolean)

    Lambda表达是作为回调

    一个标准的委托应用场景,processList方法遍历列表中的每个元素,检查是否需要处理该项,然后进行一些处理。

    Public Delegate Function ShouldProcess(Of T)(element As T) As Boolean
     
        Sub ProcessList(Of T)( _
                    elements As List(Of T), shouldProcess As ShouldProcess(Of T))
    
            For Each elem In elements
                If shouldProcess(elem) Then
                    'do some processing here
                End If
            Next
        End Sub
    在没有使用lambda之类的使用办法:
    Public Class Person
        Public Age As Integer
    End Class
     
     Function _PrivateShouldProcess(person As Person) As Boolean
            Return person.Age > 50
     End Function
     
     Sub DoIt()
            Dim list As New List(Of Person)
            ProcessList(list, AddressOf _PrivateShouldProcess)
     End Sub
    有了lambda之后的写法:
     Sub DoItAgain()
         Dim list As New List(Of Person)
         ProcessList(list, Function(person As Person) person.Age > 50)
     End Sub
    有了lambda表达式后,不需要创建你自己打函数来执行处理逻辑。只有在需要使用的地方才定义委托。
    lambda表达式具有强大功能和便携性,并且使你的代码更便于阅读和维护。比如,类型推断。
     

    类型推断

      'lambda 类型推断 
       Dim lambda As Func(Of Integer, Integer) = Function(x) x * x
    示例中,lambda变量的类型被定为func(of integer,integer)。这是一个接受一个整型参数,并返回一个整数参数的委托。因此,编译器自动推断lambda参数x是整数,且lambda的返回值是整数。
     
    在调用接受委托的方法是,你同样会享受到lambda表达式参数推断带来的益处。我们可以将上文中的DoItAggin()重新定义:
        Sub DoItAgain()
            Dim list As New List(Of Person)
            ProcessList(list, Function(person) person.Age > 50)
        End Sub
    推断结果,如果没有定义委托类型,并想让编译器合成一个,这种情况相当简单。
       Dim lambda1 = Function(x As Integer) x * x
    示例中,lambda表达式是完全类型(lambda参数x是整数类型,编译器推断出返回值是整数,因为整数×整数= 整数)。然而lambda1变量没有类型。因此,编译器会合成一个与lambda表达式形状相匹配的匿名委托,然后将该委托类型分配给lambda1。这意味着,能够动态创建lambda表达式而无需静态构造他们的委托类型。
    场景1:
    描述:面临这样一种情况,你需要一个对一组变量进行检查的条件判断逻辑,并且这个条件判断逻辑会被使用到若干地方。
    Public Class Motorcycle
    
        Public Property Color() As String
        Public Property Cc() As Integer
        Public Property Weight() As Integer
    End Class
    
    Public Class TestRun
    
        Public Sub PrintReport(motorcycle As Motorcycle)
    
            If motorcycle.Color = "Red" And motorcycle.Cc = 60 And _
                motorcycle.Weight > 300 And motorcycle.Weight < 400 Then
    
                'do something here 
            End If
            'do something here
            If motorcycle.Color = "Red" And motorcycle.Cc = 60 And _
                motorcycle.Weight > 300 And motorcycle.Weight < 400 Then
    
                'do something here 
            End If
    
        End Sub
    很可能,最容易想到的是将判断逻辑提取到方法中,然后进行复用。但是我们此处的条件判断逻辑有在这一个函数中使用,而其他地方都用不到。不建议以上做法。这样,我们的类被仅用于支持此函数的帮助函数(即,提取出的条件判读函数)弄乱。这样做会对可维护性造成负面影响,例如,别人调用了这个帮助函数,而我需要修改呢?
    改进后的做法:
        Public Sub PrintAgain(motorcycle As Motorcycle)
            Dim check = Function(m As Motorcycle) m.Color = "Red" And _
                            m.Cc = 60 And m.Weight > 300 And m.Weight < 400
            If check(motorcycle) Then
                'do something
            End If
            'do something
            If check(motorcycle) Then
                'do something
            End If
    
        End Sub
    我们已经将条件判断逻辑提取处理,以便检查motorcycle类中的一些条件。而不是将这些逻辑放入到一个隐蔽的私有方法中。通过lambda表达式,让编译器自动创建委托类型,并与所有必需的工作联系起来。这样可以像调用方法一样调用lambda表达式。

    Lambda代码生成的实质

    之前我们的代码:

    Sub TestLambda()
        Dim doubleIt As Func(Of Integer, Integer) = _
            Function(x As Integer) x * 2
        Console.WriteLine(doubleIt(10))
    End Sub
    我们知道func是一个委托,而委托是一个函数指针,那么编译器是如何发挥功能的?在此例中,编译器为你生成了新的函数,并设置委托,使其指向新的函数:
    Function $GeneratedFunction$(x As Integer) As Integer
        Return x * 2
    End Sub
    
    Sub TestLambda()
        Dim doubleIt As Func(Of Integer, Integer) = _
            AddressOf $GeneratedFunction$
        Console.WriteLine(doubleIt(10))
    End Sub
    编译器实质上接受 lambda 表达式,并根据它的内容创建新的函数,然后改变赋值语句,所以 lambda 表达式将采用所生成函数的地址。在这种情况下,该函数在含有使用 lambda 表达式的方法的相同父项中生成。如果 TestLambda 在类 C 上定义,那么生成的函数将在 C 上定义。请注意,生成的函数是不可调用的,且标记为私有。

    Lambda表达变量--闭包

    前面的示例中,lambda表达式中的参数是通过参数进行传递的(绑定变量)。
    在数学中,lambda计算中的基本概念是,拥有自由变量或绑定变量。
    自由变量,是指那些定义在方法中的局部变量或者参数。
    绑定变量,是指那些在lambda签名中定义的变量。
         Dim y As Integer = 10
         Dim addTen As Func(Of Integer, Integer) = Function(x) x + y
    在上面的代码中,x 因为是lambda表达式的形参,所以被认定为lambda中的一个绑定变量;而y 因为属于lambda表达式所在函数的局部变量,所以被认定为自由变量。
    在定义了lambda表达式之后,它被看作是一个委托类型。看下面的例子:
        Function MakeLambda() As Func(Of Integer, Integer)
            Dim y = 10
            Dim addTen As Func(Of Integer, Integer) = Function(x) x + y
            Return addTen
        End Function
    
        Sub Uselambda()
            Dim addTen = MakeLambda()
            Console.WriteLine(addTen(5))
        End Sub
    执行上面的代码,你会发现控制台输出的是15.你可能会想,这是如何实现的,函数Makelambda将y定义为局部变量,而且lambda正在使用y,但lambda是从函数makelambda返回的。函数UseLambda从Makelambda中得到lambda并执行,这看起来有些像是,变量y被记住了。
    y的生存周期是makeLambda的方法。当我们执行从makelambda返回的lambda时,makelambda会超出范围,且应清除它的堆栈空间。但是y在堆栈上定义的,此时它会与lambda粘滞。
    这种粘滞就是奇妙所在,通常称为变量提升。在这种情况下,变量y称为提升变量。并且,如你所见,提升变量很强大,编译器为你做了很多辅助工作,以获得变量的状态,并在它们的正常生产期之外继续保留它们。
    更正式地说,当编译器遇到含有自由变量的lambda表达式时,它会把自由变量提升为闭包的类。闭包的生存周期超出了在其中承载的自由变量的生存周期。 
    正如前面所分析的,x与lambda的参数绑定,而y是自由变量。编译器探测到这些,并继续创建一个捕获自由变量以及为lambda表达式定义实现一个闭包类。
    Public Class _Closure$__1
        Public y As Integer
        Public Function _Lambda$__1(ByVal x As Integer) As Integer
            Return x + Me.y
        End Function
    End Class
    再看下面的示例:
        Sub TestLambda()
            Dim y = 10
            Dim lambda = Function(x As Integer) x + y
            y = 20
            Console.WriteLine(lambda(5))
        End Sub
     显示的结果应该是25,在lambda执行之际,y的值变为20,因此当lambda执行之后,它返回20+5.

    充分利通lambda表达式

    if运算符:
         Dim conditionCheck = Function(x1 As Integer, y As Integer) x1 > y
         Dim x = If(conditionCheck(10, 20), 10, 20)
     if关键字与iif函数调用类似,唯一不同的是if关键是类型安全的。这意味着上面的例子中,编译器会推断if关键字的两个分支返回一个整数,因此,它可以推断出x的类型是integer
    lambda表达式中,使用if关键字
         Dim x = Function(c As Customer) _
                     If(c.CustomerId = 4, c.FirstName, c.LastName)
     
     
     
     参考:http://msdn.microsoft.com/zh-cn/magazine/cc163362.aspx

    追加:vb中在lambda表达式中,写多句表达式

         Dim f1 = Function(s)
                      Console.WriteLine(s)
                      Return s
                   End Function
    
         Dim f1T As Func(Of String, String) = _
                Function(s)
                    Console.WriteLine(s)
                    Return s
                End Function
            Dim colr1 = Sub(strValue As String, intA As Integer, intB As Integer)
                            Dim asda As New Motorcycle()
                            asda.Cc = strValue
                            asda.Color = intA
                            asda.Weight = intB
                        End Sub
  • 相关阅读:
    myaql常用函数
    mysql常用表/视图管理语句
    mysql中select五种子句和统计函数
    mysql里表以及列的增删改查
    mysql列类型
    如何删除openfire for苹果,彻底卸载!
    XMPP 服务器 Openfire 的 Emoji 支持问题(进行部分修改)
    iOS5.1下emoji表情显示方框的解决办法
    iOS 获取字符串中的单个字符
    iOS XMPP之常见错误一:(<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>)
  • 原文地址:https://www.cnblogs.com/RealAlex/p/3178581.html
Copyright © 2020-2023  润新知