我们都知道,在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类似的效果.