golang 日常開發之巧用 defer

我們都知道,在 golang 中,有一種語言特性跟 C++ 中的 RAII 特別相似,那就是 defer。例如以下兩段代碼便可實現相同的效果

#include <iostream>

class Defer {
    public:
        Defer() { }

        ~Defer() {
            std::cout << "defer" << std::endl;
        }

};

int main() {
    Defer d;
    return 0
}
import "fmt"

func main() {
 defer func() {
  fmt.Println("defer")
 }()
}

上述兩段代碼都會在 main 函數退出時,打印出字符串 "defer"

但是 golang 中的 defer 和 c++ 中的 RAII 還是有不同之處的。在 c++ 中,RAII 作用於對象的作用域,當離開對象作用域時,便觸發 RAII 的執行,而一個函數中可能包含很多個不同的作用域。

int main() {
    // 循環體內的作用域
    for (size_t i=0; i<10; i++) {
        Defer d; // 打印10次defer
    }

    // 花括號構成的作用域
    {
        Defer d; // 打印1次defer
    }
    return 0
}

而 golang 中沒有作用域的概念,它不同於 c++ 依賴程序員自行管理內存,golang 是帶 GC 的自動語言,對象的回收時機是程序員無法精確控制時機的。因此 golang 中 defer 只會在當前函數返回前才觸發執行。那麼有沒有辦法達到與 c++ 中 RAII 類似的效果呢?答案是有的,通過創建匿名函數即可。

func printDefer() {
 fmt.Println("defer")
}

func main() {
 for i  := 0; i < 10; i++ {
        func() {
            defer printDefer()
        }()
 }

  func() {
    defer printDefer()
  }()
}

通過上述 golang 代碼便可達到與 c++ RAII 類似的效果.

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/wofr1DKoBbJ1wlMTXiPncw