做短视频的网站,wordpress移动下方的菜单,深圳注册公司地址怎么解决,网站规划与网页设计第二版文章目录 匿名函数匿名函数的定义匿名函数作为参数传递匿名函数的缺点 lambda表达式什么是lambda表达式闭包 匿名函数
为什么我们要使用匿名函数#xff1f;匿名函数存在的意义是为了简化一些函数的定义#xff0c;特别是那些定义了之后只会被调用一次的函数#xff0c;与其… 文章目录 匿名函数匿名函数的定义匿名函数作为参数传递匿名函数的缺点 lambda表达式什么是lambda表达式闭包 匿名函数
为什么我们要使用匿名函数匿名函数存在的意义是为了简化一些函数的定义特别是那些定义了之后只会被调用一次的函数与其大费周折拖动文件然后定义在类中的某个位置匿名函数将更加方便简洁。
匿名函数的定义
以下两种无参数匿名函数
Action A delegate { Debug.Log(Hello); };
A delegate ()
{Debug.Log(Hello);
};匿名函数声明需要配合委托使用并且声明时需要在函数头加上delegate匿名函数的无参构造可以省略括号。 匿名函数定义不允许使用泛型很好理解泛型是为了函数调用时能够灵活地接受不同类型的参数但是使用匿名函数意味着它只会被调用一次与其使用泛型不如让我们直接指定
Actionint, string A delegate (int i, string s)
{int q Int32.Parse(s) i;
};定义带参数的匿名函数只需像正常函数定义即可。如果需要返回值只需使用Func
Funcint, string,int A delegate (int i, string s)
{int q Int32.Parse(s) i;return q;
};匿名函数作为参数传递
现有如下定义 class Test{public Action action;public void Dosomething(int a ,Action fun){fun();}public Action MyFun(){return delegate () { Debug.Log(返回委托类型的匿名函数); };}}在上述类中我们定义了两个方法Dosomething需要传入一个Action委托funMyfun则返回一个Action类型的返回值定义的委托是可以作为返回值类型的在其中我们将一个匿名函数作为委托类型的返回值。 void Start(){Test t new Test();t.Dosomething(1, delegate { Debug.Log(匿名函数作为参数传入); });Action A delegate { Debug.Log(委托装载匿名函数并作为参数传入)); };t.Dosomething(1, A);}匿名函数可以作为委托类型的参数传入。也可以返回时作为委托类型猜测应当是匿名函数作为参数传递时自动被封装为了对应委托 void Start(){Test t new Test();t.action t.MyFun();t.action(); // 输出返回委托类型的匿名函数t.MyFun()(); // 只有委托返回值类型才能这么使用调用函数后再加个括号直接调用委托}委托类型返回值的函数在调用后再加上括号可以直接调用该委托。 匿名函数的缺点
使用匿名函数的最大优点就是方便但是匿名函数最大的缺点就是匿名如下所示
Action A delegate { Debug.Log(你好); };
A - delegate { Debug.Log(你好); }; // 无效
A();// 依旧会输出你好因为匿名函数无法删除
A null; // 只有清空A才能从中删除匿名函数想要删除委托中的匿名函数即使我们在A中减去相同定义的匿名函数也无济于事因为此函数非彼函数。匿名函数没有函数名也就无法被减去即使我们定义了相同的匿名函数他们的地址本质上也不是同一个函数。
所以如果一个委托只存一个函数那就可以使用匿名函数但是如果一个委托存在多个函数那么当你想要去除这个匿名函数的时候就只能清空这个委托。所以在设计使用匿名函数的时候要么用一个委托只存储匿名函数要么作为参数传入委托类型的返回值的函数进行调用就像上述的t.MyFun()();。 lambda表达式
什么是lambda表达式
lambda表达式就是匿名函数的一种创建方式使用lambda表达式可以省略匿名函数的delegate定义
Action A () { Debug.Log(你好); };lambda表达式省略了delegate关键字并使用 lambda 声明运算符来声明。 同理有参和有返回的lambda表达式也和匿名函数的定义相同。 Actionint, string B (int i, string s) {int q Int32.Parse(s) i;};Funcint, string,int C (int i, string s) {int q Int32.Parse(s) i;return q;};// 委托已经指定类型可以省略参数类型Funcint, string,int C (i, s) {int q Int32.Parse(s) i;return q;};当lambda表达式只执行一个语句的时候连花括号都不需要了 使用空括号指定0个输入参数
Action line () Console.WriteLine();不带返回值类型的lambda表达式的简洁用法单个参数可以省略小括号
Actionint square x Console.WriteLine(x);甚至lambda表达式可以省略返回值定义只需定义委托类型即可
Funcint, int square x x * x; // return x*x在带返回值类型的委托中省略return
Funcint, int, bool testForEquality (x, y) x y; //多个入参还是需要括号和逗号区分的在多个入参的情况下lambda用弃元来表示哪些参数不被使用 多嘴一下在委托定义了入参数量然后lambda表达式需要使用到的入参比定义的入参数量少的情况下当然可以使用弃元。但是作为添加到委托内的匿名函数如果委托需要装载多个函数的话实际上不太适合使用匿名函数
Funcint, int, int constant (_, _) 42;闭包
关于闭包的具体说明已经在此文【Lua学习笔记】Lua进阶——函数和闭包中解释过了此处便不再赘述。
简单来说闭包就是内部函数引用了外部函数的变量导致本应该在栈中释放的外部函数的生命周期遭到改变延长。这个这些变量被我们称为upvalues它们原本的作用域是外部函数但是随着内部函数的使用它们的作用域又包括了内部函数。
就如同下面的例子
public event Action action;
public void Test()
{int value 100;action () { Debug.Log(value); };//使用了value但value作用域在函数Test而非匿名函数内
}上述例子中我们在匿名函数内部使用了外部函数Test的变量value结果是可以正常执行的。照理说局部变量value在Test中没被使用就会释放但是匿名函数的使用延长了它的生命周期这就是闭包。
再看下列的例子
public void Test()
{for (int i 0; i 10; i){action () { Debug.Log(i); };}
}
action();当我们执行上述语句的时候输出答案是什么可能你以为是0123456789但真正的答案是输出10次10原因其实也很简单在委托中存储了十个匿名函数每个的指令是输出i但是不要忘了i是upvalue它不是赋值到内部这个匿名函数的局部变量而是匿名函数直接调用在外部函数的i的值当循环结束时i10本应当释放的i的生命周期得到了延长当我们执行委托的时候则匿名函数才会调用这个i而此时i10因此输出了10次10。
public void Test()
{for (int i 0; i 10; i){int index i;action () { Debug.Log(index); };}
}
action();然而使用int index i则可以实现上述功能原因在于它是值类型的变量我们每次在for循环中int一个index实际上都是声明了一个新的int变量。所以每个匿名函数调用的index实际上是10个不同的index。
如果害怕lambda表达式不小心捕获了外部函数的upvalue则可以使用static关键字进行限制
Funcdouble, double square static x x * x;