容易忽略的遞歸當中的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並沒有改變。

造成我們直覺上的錯誤其實就是我一開始說的那種固有思維,代碼中變量被賦值后,下面代碼沒有再操作這個值 那么這個值應該是被修改后的值;當然這種思維在沒有遞歸代碼當中肯定是正確的。

當我們遞歸寫的少的情況很容易造成以上那種直覺上的錯誤判斷。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM