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 sEnd 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
Lambda 笔记的更多相关文章
- 0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...
- 委托学习笔记后续:泛型委托及委托中所涉及到匿名方法、Lambda表达式
引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到和委托相关的匿名方法.Lambda表达式及泛型委托记录 ...
- 《C#本质论》读书笔记(12)委托和Lambda表达式
12.1.委托概述 12.1.2 委托的数据类型 为了减少重复代码数量,可以将比较方法作为参数传递给 BubbleSort()方法.此外,为了将方法作为参数传递,必须有一个能够标识方法的数据类型--也 ...
- Java8学习笔记----Lambda表达式 (转)
Java8学习笔记----Lambda表达式 天锦 2014-03-24 16:43:30 发表于:ATA之家 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人 ...
- Java开发笔记(六十一)Lambda表达式
前面介绍了匿名内部类的简单用法,通过在sort方法中运用匿名内部类,不但能够简化代码数量,还能保持业务代码的连续性.只是匿名内部类的结构仍显啰嗦,虽然它省去了内部类的名称,但是花括号里面的方法定义代码 ...
- HTML5学习笔记(十九):Lambda和Promise
Lambda 在ES6的标准中称为Arrow Function(箭头函数).下面是一个简单的箭头函数: x => x * x 上面的定义和下面的代码定义效果一样: function (x) { ...
- Python学习笔记010——匿名函数lambda
1 语法 my_lambda = lambda arg1, arg2 : arg1 + arg2 + 1 arg1.arg2:参数 arg1 + arg2 + 1 :表达式 2 描述 匿名函数不需要r ...
- lambda表达式笔记
前几天一位好友分享了一篇文章,其中讲到了lambda表达式,正好最近看了一些内容,就做做笔记吧... lambda表达式服务于函数式接口,如果需要一个函数式接口的对象时,就可以用lambda表达式代替 ...
- C# Lambda表达式学习笔记
本笔记摘抄自:https://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html,记录一下学习过程以备后续查用. 一.Lambda ...
随机推荐
- STL-空间配置器(allocator)
STL的空间配置器作为STL六大部件的重要组成部分,它总是隐藏在一切组件的背后.它主要负责动态空间的分配.释放等管理工作.整个STL的操作对象(所有的数值)都存放在容器之内,而容器一定需要配置空间以置 ...
- C++ 约瑟夫环
约瑟夫环: 已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又出列:依此规律重复下去,直到圆桌周 ...
- addChildViewController 用法
// // SCMyOrderViewController.m // SmartCommunity // // Created by chenhuan on 15/9/7. // Copyright ...
- ios 实时刷新屏幕
index=; // timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:layer selector:@selector(setNe ...
- Flume笔记--source端监听目录,sink端上传到HDFS
官方文档参数解释:http://flume.apache.org/FlumeUserGuide.html#hdfs-sink 需要注意:文件格式,fileType=DataStream 默认为Sequ ...
- TableView_图片异步加载 KVO
TableView 异步下载图片 ImageDownloader.h #pragma mark - 声明block //1,声明block typedef void(^Result) (UIImage ...
- Linux下使用QQ的几种方式
Linux下没有官方的QQ聊天应用,对于经常使用QQ与朋友同事沟通交流的小伙伴们来说肯定很不方便,在Linux下可以使用以下几种方法使用QQ: 1.wine qq for linux Ubuntu ...
- SwitchySharp怎样设置 ( proxy switch!的设置与使用方法)
规则列表URL https://autoproxy-G{过}F{滤}Wlist.googlecode.com/svn/trunk/G{过}F{滤}Wlist.txt 注:不同的代{过}{滤}理 相 ...
- monogdb笔记1
:db.collection.remove()与db.collection.drop()的比较 插入100万条测试数据 ;i<;i++){ db.tester.insert({-i}) } 进行 ...
- Moving Acerage
http://zh.wikipedia.org/zh/%E7%A7%BB%E5%8B%95%E5%B9%B3%E5%9D%87