1. Go defer 去掉閉包函數(shù),靠譜嗎?

        共 2901字,需瀏覽 6分鐘

         ·

        2023-07-19 17:37

        大家好,我是煎魚。

        在 Go 語言里,defer 關(guān)鍵字是大家很愛用的。因為他有著 defer+recover+panic 的組合拳打法,還有種各種 defer close 等常用場景。

        這是 Go 語言開發(fā)者必知必會的編程姿勢。

        defer 常見用法

        在語法上,Go defer 的代碼示例如下:

              package?main

        import?"fmt"

        func?main()?{
        ?defer?fmt.Println("煎魚你好!")

        ?fmt.Println("放學(xué)別走")
        }

        輸出結(jié)果:

              放學(xué)別走
        煎魚你好!

        那 defer 在 Go 里的常見用法有哪些呢?首先是上文用到的,直接 defer + 函數(shù):

              defer?f()

        其次是 defer+閉包的方式:

              defer?func()?{?
        ???result?:=?f()
        ???//?do?something?with?result
        }()

        其他還有在面試題上常被考究的傳參變形:

              func?f1()?int?{
        ?i?:=?1
        ?defer?func()?{
        ??i++
        ?}()
        ?...
        }
        func?f2()?int?{
        ?i?:=?1
        ?defer?func(i?int)?{
        ??i++
        ?}(i)
        ?....
        }

        這些代碼看起來,我們總是在對 defer 做閉包的各種聲明和使用。defer 會不會就是和閉包天生一對?

        新提案:defer 代碼塊

        最近大家也在討論一個與之相關(guān)的 Go 提案《proposal: Go 2: deferred code blocks[1]》,由 @Damien Lloyd 提出,想看看有沒有機會把 defer 的新語法落地。

        4eb7ac035efcae353edfb01fcbdaa081.webp

        原作者在使用 defer 時也是經(jīng)常:

              defer?f()

        但這樣就無法獲得返回值。最終要變成:

              defer?func()?{?
        ???result?:=?f()
        ???//?do?something?with?result
        }()

        基于上述類似的原因,想引入如下具有 defer 作用的代碼塊語法:

              defer?{
        ???//?在封閉函數(shù)的末尾執(zhí)行此操作
        }

        在使用了 defer 關(guān)鍵字的函數(shù)最后執(zhí)行這整個代碼塊 {...}。代碼塊中的每一行將按順序運行。

        作者給出的代碼示例:

              func?fn()?{
        ????f,?err?:=?os.Create("eddycjy.txt")
        ????if?err?!=?nil?{
        ????????panic(err)
        ????}

        ????defer?{
        ???????err?:=?f.Close()

        ???????if?err?!=?nil?{
        ??????????panic(err)
        ???????}
        ????}
        }

        在 fn 函數(shù),聲明了 defer {...},代碼塊內(nèi)是對 f.Close 的兜底判斷和異常拋出。在函數(shù)結(jié)束后執(zhí)行這整個代碼塊。

        反對的聲音

        當然,這看著似乎是比較美好的??雌饋碓岚缸髡咧皇呛喕?defer 是的閉包使用,調(diào)整了作用域的范圍。

        但在社區(qū)內(nèi)其實遭受比較多的反對聲音。包含但不限于以下幾點:

        1、收益比不高:這個提案只是避免了 func()() 等閉包聲明,但是卻要增加新的 defer 語法(語言語法更改會帶來高昂成本),這個變更的 ROI 不高。

        2、破壞兼容性:原 defer 關(guān)鍵字調(diào)用總是會跟著函數(shù)的詞法調(diào)用,有良好的一致性。如果進行修改,會產(chǎn)生新的隱晦,破壞一致性。也會對現(xiàn)有的許多工具(例如:靜態(tài)分析工具)產(chǎn)生影響,全要改。

        3、作用域問題:原本 defer func{}() 的代碼塊結(jié)構(gòu)下,你的代碼作用域都限于閉包函數(shù)下。而使用新的 defer {} 的結(jié)構(gòu),該返回和操作,是否會影響到外部函數(shù)的結(jié)果?(這是最有爭議的一點,作者也比較前言不搭后語,沒明確指明語法意思)

        總結(jié)

        一開始乍一眼一看,感覺只是把 defer 關(guān)鍵字語句簡化一下,好像特別好,省了幾個單詞。就像 if err != nil 也會有提要用 Rust 的 ? 等用法來替代的。

        經(jīng)過社區(qū)網(wǎng)友們指出后,發(fā)現(xiàn)這里貓膩不少。一門已經(jīng)有 10+ 年的編程語言,還有 Go1 兼容性保障的。做出這類帶作用域的提案變更,是有比較大的風險的。

        同時對于 Go 工具鏈的影響,也是非常大的。一改,直接都完犢子了。確實需要盡量深思。原作者完全沒提到。

        該提案,我寫的時候正在開放 3 周等待意見收集。很神奇,沒更多的人說話,但提案的表情給了很多個不認同。

        1803ba14b86e86b5d246417d86a3f25a.webp

        推薦閱讀


        參考資料 [1]

        proposal: Go 2: deferred code blocks: https://github.com/golang/go/issues/38520


        關(guān)注和加煎魚微信,

        一手消息和知識,拉你進技術(shù)交流群??


        7ff34319198c744481e957e5694aff6c.webp


        你好,我是煎魚,出版過 Go 暢銷書《Go 語言編程之旅》,再到獲得 GOP(Go 領(lǐng)域最有觀點專家)榮譽,點擊藍字查看我的出書之路

        日常分享高質(zhì)量文章,輸出 Go 面試、工作經(jīng)驗、架構(gòu)設(shè)計,加微信拉讀者交流群,和大家交流!

        瀏覽 33
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 寡妇高潮一级毛片免费看大胸 | 亚洲在线视频 | 操逼福利社 | 中国偷窥成熟视频 | 国产精品久久久久久三级精品 |