容易忽略的遞歸當中的return

先描述問題。異步

最近項目有個需求,數據入庫失敗後延時必定時間而後從新入庫;當失敗達到必定次數後就再也不進行入庫,由於項目簡單,也不須要異步處理。因此看到這個問題很容易想到用遞歸去實現。測試

我最開始的代碼example:spa

/// <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了。code

實際結果應該是1 緣由很簡單,catch裏的return 是遞歸這個方法中的return。這個時候TestFun並無所有退出,只是退出了遞歸的那一層而已。遞歸退出完了 也就是catch語句塊執行完畢後,會繼續執行return1。blog

 

這個問題自己並不難理解,只是咱們都有個固有的思惟 方法中return了 就不會執行下面代碼了。而後就會忽略下面的遞歸調用。遞歸

 

說到固有思惟我再舉個例子仍是這個問題。it

 /// <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了。io

 

正確結果其實也是返回1。說到底仍是由於遞歸,咱們catch 裏的result=0 實際上是針對當前遞歸這個方法裏面的result。由於咱們先遞歸後改變值的;class

咱們能夠這樣去想象:當我一次遞歸時咱們方法是TestFun1 第二次是TestFun2 第三次是 TestFun3  裏面的代碼仍是同樣的。因此我catch裏面的result實際上是對應我TestFun3 裏的result。直到咱們退出遞歸回到最初的方法裏面即TestFun 時它的result仍是1並無改變。變量

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

當咱們遞歸寫的少的狀況很容易形成以上那種直覺上的錯誤判斷。

相關文章
相關標籤/搜索