<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 4.4 錯誤語義 我們其實已經在前面的討論中詳細討論過了錯誤值檢查與錯誤上下文的增強手段, 處理方式啰嗦而冗長,減少這種代碼出現的密集程度真的是一個實際的問題嗎?換句話說: 社區里怨聲載道的冗長的錯誤處理語義,真的有必要進行改進嗎? ### 4.4.1 check/handle 關鍵字 Go 團隊在重新考慮錯誤處理的時候提出過兩種不同的方案, 由 Russ Cox 提出的第一種方案就是引入新的關鍵字`check`/`handle` 進行組合。 我們來看這樣一個復制文件的例子。復制文件操作涉及到源文件的打開、目標文件的創建、 內容的復制、源文件和目標文件的關閉。這之間任何一個環節出錯,都需要錯誤進行處理: ``` func CopyFile(src, dst string) error { r, err := os.Open(src) if err != nil { return fmt.Errorf("copy %s %s: %v", src, dst, err) } defer r.Close() w, err := os.Create(dst) if err != nil { return fmt.Errorf("copy %s %s: %v", src, dst, err) } if _, err := io.Copy(w, r); err != nil { w.Close() os.Remove(dst) return fmt.Errorf("copy %s %s: %v", src, dst, err) } if err := w.Close(); err != nil { os.Remove(dst) return fmt.Errorf("copy %s %s: %v", src, dst, err) } } ``` 在使用`check`/`handle`組合后,我們可以將前面的代碼進行化簡,較少`if err != nil`的出現頻率,并統一在`handle` 代碼塊中對錯誤進行處理: ``` func CopyFile(src, dst string) error { handle err { return fmt.Errorf("copy %s %s: %v", src, dst, err) } r := check os.Open(src) defer r.Close() w := check os.Create(dst) handle err { w.Close() os.Remove(dst) // (only if a check fails) } check io.Copy(w, r) check w.Close() // 此處發生 err 調用上方的 handle 塊時還會再額外調用一次 w.Close() return nil } ``` 這種使用`check`和`handle`的方式會當`err`發生時,直接進入`check`關鍵字上方 最近的一個`handle err`塊進行錯誤處理。在官方的這個例子中其實就已經發生了語言上模棱兩可的地方, 當函數最下方的`w.Close`產生調用時, 上方與其最近的一個`handle err`還會再一次調用`w.Close`,這其實是多余的。 此外,這種方式看似對代碼進行了簡化,但仔細一看這種方式與`defer`函數進行錯誤處理之間, 除了減少了`if err != nil { return err }`出現的頻率,并沒有帶來任何本質區別。 例如,我們完全可以使用`defer`來實現`handle`的功能: ``` func CopyFile(src, dst string) (err error) { defer func() { if err != nil { err = fmt.Errorf("copy %s %s: %v", src, dst, err) } }() r, err := os.Open(src) if err != nil { return } defer r.Close() w, err := os.Create(dst) if err != nil { return } defer func() { if err != nil { w.Close() os.Remove(dst) } }() _, err = io.Copy(w, r) if err != nil { return } err = w.Close() if err != nil { return } } ``` 在仔細衡量后不難看出,`check`/`handle`關鍵字的設計中,`handle`僅僅只是對現有的語義的一個化簡。 具體來說,`handle`關鍵字等價于`defer`: ``` handle err { ... } =&gt; defer func() { if err != nil { err = ... } }() ``` 而`check`關鍵字則等價于: ``` check F() => err = F() if err != nil { return } ``` 那么能不能僅實現一個`check`關鍵字呢? ### 4.4.2 內建函數`try()` 緊隨`check/handle`的提案,Robert Griesemer 提出了使用內建函數`try()`配合延遲語句來替代`check`,它能夠接收最后一個返回值為`error`的函數, 并將除`error`之外的返回值進行返回,即: ``` x1, x2, ..., xn = try(F()) => t1, ..., tn, te := F() if te != nil { err = te return } x1, ..., xn = t1, ..., tn ``` 有了`try()`函數后,可以將復制文件例子中的代碼化簡為: ``` func CopyFile(src, dst string) (err error) { defer func() { if err != nil { err = fmt.Errorf("copy %s %s: %v", src, dst, err) } }() r := try(os.Open(src)) defer r.Close() w := try(os.Create(dst)) defer func() { w.Close() if err != nil { os.Remove(dst) // 僅當 try 失敗時才調用 } }() try(io.Copy(w, r)) try(w.Close()) return nil } ``` 可見,這種做法與`check/handle`的關鍵字組合本質上也沒有代碼更多思想上的變化, 尤其是`try()`內建函數僅僅在在形式上對`if err != nil { ... }`起到了化簡的作用。 但這一錯誤處理語義并沒有在最后被納入語言規范。 這一設計被拒絕的核心原因是`try()`函數將使對錯誤的調試變得不夠透明, 其本質在于將一個顯式返回的錯誤值進行隱藏。例如,在調試過程中由于被調試函數被包裹在`try()`內,這種不包含錯誤分支的代碼形式,對追蹤錯誤本身是一個毀滅性的打擊,為此用戶不得不在調試時 引入錯誤分支,在調試結束后將錯誤分支消除,煩瑣不堪。 我們從這前后兩份提案中,可以看到 Go 團隊將錯誤處理語義上的改進與 『如何減少`if err != nil { ... }`的出現』直接化了等號,這種純粹寫法風格上的問題, 與 Go 語言早期設計中顯式錯誤值的設計相比,就顯得相形見絀了。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看