容易忽略的递归当中的return

先描述问题。

最近项目有个需求,数据入库失败后延时一定时间然后重新入库;当失败达到一定次数后就不再进行入库,因为项目简单,也不需要异步处理。所以看到这个问题很容易想到用递归去实现。

我最开始的代码example:

/// <summary>
        /// 错误次数
        /// </summary>
        static int errorCount = 0;

        /// <summary>
        /// 测试递归代码
        /// </summary>
        /// <returns></returns>
        static int TestFun()
        {
            try
            {
                Console.WriteLine("enter fun ");
                int a = 0;
                int n = 3 / a;
            }
            catch (Exception ex)
            {
                if (errorCount >= 3)
                {
                    Console.WriteLine("number of error==3 bye");
                    return 0;
                }
                errorCount++;
                Thread.Sleep(1000);
                TestFun();
            }
            return 1;
        }

 

这个代码我想很多人第一眼看到就很容易想到这个TestFun方法一定返回0,因为除数不能为0 所以一直报错 直到错误大于3 return了。

实际结果应该是1 原因很简单,catch里的return 是递归这个方法中的return。这个时候TestFun并没有全部退出,只是退出了递归的那一层而已。递归退出完了 也就是catch语句块执行完毕后,会继续执行return1。

 

这个问题本身并不难理解,只是我们都有个固有的思维 方法中return了 就不会执行下面代码了。然后就会忽略下面的递归调用。

 

说到固有思维我再举个例子还是这个问题。

 /// <summary>
        /// 测试递归代码
        /// </summary>
        /// <returns></returns>
        static int TestFun()
        {
            int result = 1;
            try
            {
                Console.WriteLine("enter fun ");
                int a = 0;
                int n = 3 / a;
            }
            catch (Exception ex)
            {
                if (errorCount >= 3)
                {
                    Console.WriteLine("number of error==3 bye");
                    result = 0;
                    return 0;
                }
                errorCount++;
                Thread.Sleep(1000);
                TestFun();
            }
            return result;
        }

这个代码 不直接return具体值了,而是将值保存到一个变量里。第一眼看这个代码心想这次应该要返回0了吧,出错后 result已经被赋值0了 这下最后面的return 应该返回1了。

 

正确结果其实也是返回1。说到底还是因为递归,我们catch 里的result=0 其实是针对当前递归这个方法里面的result。因为我们先递归后改变值的;

我们可以这样去想象:当我一次递归时我们方法是TestFun1 第二次是TestFun2 第三次是 TestFun3  里面的代码还是一样的。所以我catch里面的result其实是对应我TestFun3 里的result。直到我们退出递归回到最初的方法里面即TestFun 时它的result还是1并没有改变。

造成我们直觉上的错误其实就是我一开始说的那种固有思维,代码中变量被赋值后,下面代码没有再操作这个值 那么这个值应该是被修改后的值;当然这种思维在没有递归代码当中肯定是正确的。

当我们递归写的少的情况很容易造成以上那种直觉上的错误判断。

 

posted @ 2017-06-28 21:25  Cfan1236  阅读(8196)  评论(6编辑  收藏  举报