容易忽略的递归当中的return
先描述问题。
最近项目有个需求,数据入库失败后延时一定时间然后重新入库;当失败达到一定次数后就不再进行入库,因为项目简单,也不需要异步处理。所以看到这个问题很容易想到用递归去实现。
我最开始的代码example:
/// <summary>
/// 错误次数
/// </summary>
static int errorCount = ; /// <summary>
/// 测试递归代码
/// </summary>
/// <returns></returns>
static int TestFun()
{
try
{
Console.WriteLine("enter fun ");
int a = ;
int n = / a;
}
catch (Exception ex)
{
if (errorCount >= )
{
Console.WriteLine("number of error==3 bye");
return ;
}
errorCount++;
Thread.Sleep();
TestFun();
}
return ;
}
这个代码我想很多人第一眼看到就很容易想到这个TestFun方法一定返回0,因为除数不能为0 所以一直报错 直到错误大于3 return了。
实际结果应该是1 原因很简单,catch里的return 是递归这个方法中的return。这个时候TestFun并没有全部退出,只是退出了递归的那一层而已。递归退出完了 也就是catch语句块执行完毕后,会继续执行return1。
这个问题本身并不难理解,只是我们都有个固有的思维 方法中return了 就不会执行下面代码了。然后就会忽略下面的递归调用。
说到固有思维我再举个例子还是这个问题。
/// <summary>
/// 测试递归代码
/// </summary>
/// <returns></returns>
static int TestFun()
{
int result = ;
try
{
Console.WriteLine("enter fun ");
int a = ;
int n = / a;
}
catch (Exception ex)
{
if (errorCount >= )
{
Console.WriteLine("number of error==3 bye");
result = ;
return ;
}
errorCount++;
Thread.Sleep();
TestFun();
}
return result;
}
这个代码 不直接return具体值了,而是将值保存到一个变量里。第一眼看这个代码心想这次应该要返回0了吧,出错后 result已经被赋值0了 这下最后面的return 应该返回1了。
正确结果其实也是返回1。说到底还是因为递归,我们catch 里的result=0 其实是针对当前递归这个方法里面的result。因为我们先递归后改变值的;
我们可以这样去想象:当我一次递归时我们方法是TestFun1 第二次是TestFun2 第三次是 TestFun3 里面的代码还是一样的。所以我catch里面的result其实是对应我TestFun3 里的result。直到我们退出递归回到最初的方法里面即TestFun 时它的result还是1并没有改变。
造成我们直觉上的错误其实就是我一开始说的那种固有思维,代码中变量被赋值后,下面代码没有再操作这个值 那么这个值应该是被修改后的值;当然这种思维在没有递归代码当中肯定是正确的。
当我们递归写的少的情况很容易造成以上那种直觉上的错误判断。
容易忽略的递归当中的return的更多相关文章
- python递归中的return"陷阱"
在做一道练习题(参照下篇博文<在当前目录下递归的查找包含指定字符串的文件>)的时候,发现函数中的return的值竟然是None,百思不得其解,尝试化繁为简,用以下的简单的代码验证了一下 问 ...
- 经常犯的错误之递归写不全return
在写递归函数的时候,只在最后一层写return,中间的过程没有return,导致结果的丢失. 举个例子 LL query(LL i, LL k) { if (sum[i] < k) { ; } ...
- python学习笔记之装饰器、递归、算法(第四天)
参考老师的博客: 金角:http://www.cnblogs.com/alex3714/articles/5161349.html 银角:http://www.cnblogs.com/wupeiqi/ ...
- iOS 阶段学习第七天笔记(函数、递归)
iOS学习(C语言)知识点整理笔记 一.函数 1)概念:具有特定功能的代码块的封装 2)函数的定义: 函数类型+函数名(形参列表) 函数类型 函数名(形参类型1 形参名1,形参类型2 形参名2 ...
- Python的递归
递归 是指函数/过程/子程序在运行过程序中直接或间接调用自身而产生的重入现象.在计算机编程里,递归指的是一个过程:函数不断引用自身,直到引用的对象已知.使用递归解决问题,思路清晰,代码少.但是在主流高 ...
- 递归、尾递归和使用Stream延迟计算优化尾递归
我们在学数据结构的时候必然会接触栈(Stack),而栈有一个重要的应用是在程序设计语言中实现递归.递归用途十分广泛,比如我们常见的阶乘,如下代码: 1234 public static int (in ...
- 傻瓜式理解递归之php递归
写程序这么久了,有时候别人会问道一些算法比如排序啊,递归啊,总是不知道该怎么去说,今天就来整理一下,让更多的人去傻瓜式的理解递归.递归在网络上有很多定义,但有这么一句话听的最多:递归就是自己调用自己! ...
- MyBatis一级缓存引起的无穷递归
MyBatis一级缓存引起的无穷递归 引言: 最近在项目中参与了一个领取优惠劵的活动,当多个用户领取同一张优惠劵的时候,使用了数据库锁控制并发,起初的设想是:如果多个人同时领一张劵,第一个到达的人领取 ...
- 算法笔记_017:递归执行顺序的探讨(Java)
目录 1 问题描述 2 解决方案 2.1 问题化简 2.2 定位输出测试 2.3 回顾总结 1 问题描述 最近两天在思考如何使用蛮力法解决旅行商问题(此问题,说白了就是如何求解n个不同字母的所有不同排 ...
随机推荐
- spring---简介
spring spring是什么? 目的:解决企业应用开发的复杂性 功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能 范围:任何Java应用 简单来说,Spring是一个轻量级的 ...
- 运维老鸟教你安装centos6.5如何选择安装包
标签:老男孩教育 Centos6.5安装选包原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://oldboy.blog.51cto.c ...
- Promise简介
Promise是ES6中的函数,规范了如何处理异步任务的回调函数,功能类似于jQuery的defferred.简单说就是通过promise对象的不同状态调用不同的回调函数.目前IE8及以下不支持,其他 ...
- 2016 UESTC Training for Dynamic Programming
强行做做试试看吧. http://acm.hust.edu.cn/vjudge/contest/124721#overview 密码:mytrain C - 柱爷与咸鱼神功 一个简单01背包. #in ...
- SmartCoder每日站立会议09
站立会议内容 今天约了在一起编程,详细确定各个页面以及消息的添加.发送等一些小的细节. 1.站立会议照片: 2.任务展板 2.燃尽图
- RabbitMQ系列教程之一:我们从最简单的事情开始!Hello World
一.简介 RabbitMQ是一个消息的代理器,用于接收和发送消息,你可以这样想,他就是一个邮局,当您把需要寄送的邮件投递到邮筒之时,你可以确定的是邮递员先生肯定会把邮件发送到需要接收邮件的人 ...
- sql还原(.mdf文件还原)
第一步: 把备份文件放到目录:C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA (默认)(这里用 MyDB.md ...
- Java经典编程题50道之十八
两个乒乓球队进行比赛,各出三人.甲队为a,b,c三人,乙队为x,y,z三人,以抽签决定比赛名单.有人向队员打听比赛的名单:a说他不和x比,c说他不和x. z比.请编程序找出三队赛手的名单. publi ...
- Maximum Subarray Sum
Maximum Subarray Sum 题意 给你一个大小为N的数组和另外一个整数M.你的目标是找到每个子数组的和对M取余数的最大值.子数组是指原数组的任意连续元素的子集. 分析 参考 求出前缀和, ...
- 关于redis内部的数据结构
最大感受,无论从设计还是源码,Redis都尽量做到简单,其中运用到的原理也通俗易懂.特别是源码,简洁易读,真正做到clean and clear, 这篇文章以unstable分支的源码为基准,先从大体 ...