admin 管理员组文章数量: 1087135
2024年3月14日发(作者:滚动公告美化代码)
从函数指针到Lambda表达式
前言
在LINQ中Lambda表达式使用非常广泛,是其中的重要组成部分。Lambda
表达式实际上是一个匿名方法,它可以包含表达式和语句,并且可用于创建委托
或表达式目录树类型。面对一种较新的概念和技术,本文试图通过从函数指针到
Lambda表达式的陈述来展示技术发展的一个脉络。
一、指向函数的指针
随着面向对象语言的普及,C语言的这一特性渐渐地被C++等面向对象语言
中的多态性所代替,然而无论多态性使用如何灵活,窃以为其根本仍然来源于斯。
因此,这里仍然用一小段代码回顾一下:
代码1:指向函数的指针
bool IsOdd (int i){ return ((i&1)= =1);}
Int* FilterArrayOfInts(int* ints,bool (*filter)(int)) //传入数组和函数,
分别用其指针接收
{ 此处将各个奇数放入数组,并返回数组名称}
void main()
{//…定义nums数组放入1-10的10个整数
int oddnums[5]=FilterArrayOfInts(nums, IsOdd); //指向函数
}
上面的代码是从数组中过滤出奇数并把结果放到另外一个数组。其中int
oddnums[5] =FilterArrayOfInts(nums, IsOdd);这一句就是指向函数的指针。
这一句使得FilterArrayOfInts这一函数的通用性得到了提升。以下我们以C#语言
为例,看看指向函数的指针在面向对象语言中的发展。
委托
在C#中,委托(delegate)是一种引用类型,在其他语言中,与委托最接近
的是函数指针,但委托(delegate)就是一种类型安全的函数指针,为此,可以
将上述代码用委托来表述:
代码2:使用委托表述筛选出奇数
public class common
{ public delegate bool IntFilter(int i);//定义了委托
public static int[] FilterArrayOfInts(int [] ints,IntFilter filter)
{ 此处各个奇数放入数组,返回数组类型}//这里面可以使用if (filter(i))
来判断奇数
void main()
{//…定义nums数组放入1-10的10个整数
Int[] oddnums=FilterArrayOfInts(nums,);//用委托调用
IsOdd方法}}
public class Application { public static bool IsOdd(int i) { return ((i&1)=
=1);}}
在代码2中delegate bool IntFilter(int i)声明了一个委托类型,在这里相当
于声明的一个指向函数的指针。一旦声明完成,就可以直接用作类型,例如上述
代码中:IntFilter filter。至此,只要是符合所声明的委托的形式的方法名都可以
被传递过来并且使用,例如在上述代码中可以用if (filter(i))来判断奇数。至
于使用哪个方法完全取决于主方法的调用,例如上述代码中:FilterArrayOfInts
(nums,)。
C#中不直接用函数指针而是使用委托的原因就涉及到另外一个问题:C#是
类型安全的语言。这里的类型安全特指内存类型安全,即类型安全代码只访问被
授权可以访问的内存位置。如果代码以任意偏移量访问内存,该偏移量超出了属
于该对象的公开字段的内存范围,则它就不是类型安全的代码。显然指针不属于
类型安全代码,这也是为什么C#使用指针时必须申明unsafe的缘故。
二、Lambda表达式
匿名方法
为此,从C#2.0开始,可以使用匿名方法来传递内联代码。匿名方法不需要
创建一个单独的IsOdd方法,只要在通常用来传递方法委托的位置指定一段筛选
代码即可[1]。这里用匿名方法改写代码2中主方法调用部分:
代码3 匿名方法传递
Int[] oddnums=FilterArrayOfInts(nums,delegate(int i){return ((i&1)=
=1);});
这样做省去了单独创建IsOdd方法了,结果仍然一样。同时,对于将来不需
要被重用的代码而言是非常好的。但是,匿名方法会导致代码冗长,也难以读懂。
因此需要有一种更加简洁的方法来表述。
使用Lambda表达式
Lambda表达式实际上是一个匿名方法。它包含表达式和语句,常用于创建
委托或表达式目录树类型。Lambda运算符“=>”的左边是输入参数(可能没有),
右边是表达式或语句块。Lambda表达式返回右边表达式的结果。其基本格式是:
(input paramenters)=>expression;其中,parameters是一个参数列表,在Lambda
只有一个输入参数时可以不适用括号,否则括号是必须的。两个或更多输入参数
由括在括号中的逗号分隔。用Lambda 表达式,可以将代码3改写为:
代码4 使用Lambda表达式
Int[] oddnums=FilterArrayOfInts(nums,i=>((i&1)= =1));
至此,将代码1到代码4中的关键代码总结一下:
int oddnums[5]=FilterArrayOfInts(nums, IsOdd); //使用函数指针
Int[] oddnums=FilterArrayOfInts(nums,);//使用命名方法
Int[] oddnums=FilterArrayOfInts(nums,delegate(int i){return ((i&1)=
=1);});//使用匿名方法
Int[] oddnums=FilterArrayOfInts(nums,i=>((i&1)= =1));//使用Lambda
表达式
后三项实际都来源于函数的指针。显然,Lambda表达式表述更加简洁,使
用更加灵活,同时,代码类型安全。
参考文献
[1][美]Joseph ,Jr著;程胜 朱新宁 杨萍译.LINQ技术详解C#2008
版[M].第1版.北京:人民邮电出版社,2009年7月:22页
作者简介:林徐,男,(1972.8-),金山职业技术学院计算机教师,讲师,工
程师,软件工程硕士学位
版权声明:本文标题:从函数指针到Lambda表达式 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://roclinux.cn/b/1710369378a569937.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论