首页 > 其他分享 >关于在循环体中使用lambda表达式拿到错误结果的问题分析

关于在循环体中使用lambda表达式拿到错误结果的问题分析

时间:2024-07-25 18:28:30浏览次数:13  
标签:闭包 循环体 变量 作用域 这个 表达式 lambda

前言: 大家好,我是代码小白Susume,这是我在cnblogs的第一篇博客。   背景: 今天在工作的时候突然发现公司的代码有一个地方好像可以优化一下。然后火树就是啪啪一顿改,自信满满的改完后直接开始测试。   问题: 那么首先放代码(ps:已经做了去敏感信息的处理) 0 键盘啪啪一顿敲是敲爽了,但是一看结果,怎么不对劲? 0 按照本来的想法,应该是要顺着for循环执行Task达到并发运行的效果,并把每次变化的i都代入lambda表达式中执行,然后打印每个i的结果。可是这个5是哪个石头缝里蹦出来的?真让人摸不着头脑。我寻思着看了下结果,有没有可能是因为Task是一个异步可等待的操作,实际执行的时间不确定,这就导致在执行lambda表达式的之前,for循环已经被主线程遍历完了呢?于是我立刻想到,我将Task改为Thread,然后手动控制thread的启动。让他在生成的时候立刻启动,那么是不是就可以完美解决这个问题了呢?

 

但是想法很美好,实际上执行返回的结果还是有问题。不过至少不全是“5轮询结束”这个输出了。说明可能对了,但是只对了一点点。

 

然后就是各种查,各种问。最后才发现原来是踩了【在闭包中对外部作用域变量的捕获的陷阱】这个坑。出现这个问题的原因是因为在C#中lambda表达式可以看做是一个闭包。当程序在一个闭包中并发调用外部作用域的变量的时候,它实际上取的并不是这个变量的当前值。而是这个变量的引用(应该可以看做是这个变量所在的地址),也就是说如果这个值最后被改变了,那么它取的就是最后改变的那个值。   闭包的概念: 所谓的闭包其实是一个抽象的概念,作为一个小白,我也不是很清楚。 不过大家可以看看黑洞大佬的这篇:https://www.cnblogs.com/eventhorizon/p/9535289.html 写的非常好,日常膜拜大佬。 之后又是各种大模型的贴心呵护下,我大概明白在C#中,如果我在一个函数中调用一个lambda函数,或者匿名方法,或者本地函数。那么对于这个外部调用方来说,这个被调用的函数(这个函数必须有权访问另一个函数的作用域中的变量)就可以看做是一个闭包。   处理: 那么理解了闭包的概念之后,回到在这个例子中,i是一个值类型(这里强调是为了搞清楚,这个闭包对外部作用域的引用实际上不是说什么对象的引用,而是捕获这个变量的地址上的值的这个引用)。但是由于代码中的lambda表达式是在每次循环进入时才生成,并且由于Task.Run()也不会立刻执行。所以当他开始执行的时候,i的值已经在for循环跑完后变为5了,也就是说lambda表达式运行的时候,它捕获了i的地址上所在的值已经是5.所以打印出来就是"5轮询结束"。 而要解决这个问题的方法,就是用一个临时变量去记住这个i的值的变化。这样我们lambda表达式在获取外部作用域的变量的时候,由于这个临时变量的值不曾改变,每个循环进来都是新的。就可以实现一开始想要的效果。代码如下:

 

实现的效果如图,确实是按照0~4输出了所有结果。

 

  总结: 那么这个坑踩了,就当然要记录一下。记录了就要吸取教训,以免以后重复踩。 给我的总结就是: 以后在闭包中调用外部作用域的变量时,一定要注意外部作用域的变量(无论是值类型的还是引用类型的)的值是否会被改变。如果存在被改变的可能,就应该用一个临时变量来保存需要的值来使用。不然容易在不知道什么时候就寄了。。。   尾言: 最后谢谢大家看我的博客,作为一个菜鸟,一个小白我的理解肯定还有很多地方不够细致,或者存在问题的地方。如果大佬们发现了,麻烦帮我指出来。谢谢各位大佬们!! 为了变强,终于,我也要开始尝试写博客了记录成长了~~   致谢: 感谢bing,感谢文心一言,感谢智谱清言,感谢chatGpt,感谢cnblogs,感谢csdn,感谢看我博客的你们~  

标签:闭包,循环体,变量,作用域,这个,表达式,lambda
From: https://www.cnblogs.com/Ureshii-fy/p/18323773

相关文章

  • Java8 函数式编程和Lambda
    lambda初识lambda表达式一个简单的方法,比较两个Integer:publicvoidTest1(){ Comparator<Integer>com=newComparator<Integer>(){ @Override publicintcompare(Integero1,Integero2){ returnInteger.compare(o1,o2); } }; TreeSet<Integer>......
  • 第3节课:运算符与表达式
    目录算术运算符加法运算符(+)减法运算符(-)乘法运算符(*)除法运算符(/)模运算符(%)复合赋值运算符赋值运算符简单赋值复合赋值递增和递减运算符递增运算符(++)递减运算符(--)表达式算术表达式赋值表达式条件表达式总结在C++编程中,运算符和表达式是构建程序逻辑的基本元素。它们......
  • AWS Lambda 没有名为“regex._regex”的模块
    我一直在尝试使用python3.9通过AWSLambda运行一些代码,但在运行代码时不断遇到问题。我不断收到“没有名为'regex._regex'的模块”错误。几天前,我在通过PyCharm在本地工作时遇到了这个问题,但我想通过安装更新​​版本的正则表达式来解决这个问题(老实说,我不记得到底是什......
  • C++11——lambda表达式
    一、前言在C++98中,如果想要对一个数据集合中的元素进行排序,可以使用std::sort方法。intmain(){ intarray[]={4,1,8,5,3,7,0,9,2,6}; //默认按照小于比较,排出来结果是升序 sort(array,array+sizeof(array)/sizeof(array[0])); //如果需要降序,需要改变元素......
  • 带有 CDK 的 Lambda 无法启动 - JSONDecodeError 和 BrokenPipeError
    我正在尝试部署一个基于图像的PythonLambda,其中包含AWSCDK库。当我尝试在AWS中运行该函数时,它无法启动。我正在使用此Dockerfile:FROMamazon/aws-lambda-python:3.12COPY*${LAMBDA_TASK_ROOT}/RUNdnfupdate-yRUNdnfinstall-ygitRUNcurl-sLhttps......
  • 带极坐标表达式的水平平均值
    我需要计算极坐标中的行平均值。我在axis的文档中没有看到pl.Expr.mean参数。作为示例,请考虑以下数据框。df=pl.DataFrame({"foo":[1,2,3],"bar":[6,7,8],})如何计算此处的行平均值?谢谢。df.select(pl.mean(["foo","bar"]......
  • 【lamda表达式】在多线程开发中的lamda表达书简化参数
    创建线程后传Runnable参数并实现run方法,可以采用下面两种方式,效果是一样的Threadt1=newThread(newRunnable(){@Overridepublicvoidrun(){//这里是线程应该执行的代码System.out.println("Hello,World!");......
  • 使用正则表达式和 Polars 有效解析公式
    我正在尝试解析一系列数学公式,并且需要使用Python中的Polars有效地提取变量名称。Polars中的正则表达式支持似乎很有限,特别是对于环视断言。有没有一种简单、有效的方法来解析公式中的符号?这是我的代码片段:importreimportpolarsaspl#Definetheregexpatte......
  • 【Python正则表达式】:文本解析与模式匹配
    文章目录1.正则表达式2.re模块3.修饰符3.元字符3-1字符匹配元字符3-2重复次数限定元字符3-3字符集合匹配元字符3-4分组元字符3-5边界匹配元字符3-6字符类别匹配元字符4.技巧4-1贪婪与非贪婪5.案例1.正则表达式正则表达式面向什么样的问题?1、判断一个字......
  • 正则表达式
    https://www.jianshu.com/p/3dd137ba2875?utm_campaign=maleskine&utm_content=note&utm_medium=seo_noteshttps://blog.csdn.net/lovedingd/article/details/128249121#匹配0-100之间数字re.match("[1-9]?\d$|100","08")#匹配邮箱163/126/qqre.......