go语言理论补充 go语言知识点( 七 )


C++的new是狗屎. new导致的问题是构造函数和普通函数的行为不一致, 这个补丁特性真的没啥优越的.
我还是喜欢C语言的 fopen 和 malloc 之类构造函数, 构造函数就是普通函数, Go语言中也是这样.
C++中, 除了构造不兼容普通函数, 析构函数也是不兼容普通函数. 这个而引入的坑有很多吧.
1.8 对象没有构造函数和析构函数
没有构造函数还好说,毕竟还有自定义的New方法 , 大致也算是构造函数了 。没有析构函数就比较难受了,没法实现RAII 。额外的人工处理资源清理工作 , 无疑加重了程序员的心智负担 。没人性?。?还嫌我们程序员加班还少吗?C++里有析构函数,Java里虽然没有析构函数但是有人家finally语句?。珿o呢,什么都没有 。没错,你有个defer,可是那个defer问题更大,详见下文吧 。
【go语言理论补充 go语言知识点】defer 可以覆盖析构函数的行为, 当然 defer 还有其他的任务. Swift2.0 也引入了一个简化版的 defer 特性.
1.9 defer语句的语义设定不甚合理
Go语言设计defer语句的出发点是好的,把释放资源的“代码”放在靠近创建资源的地方,但把释放资源的“动作”推迟(defer)到函数返回前执行 。遗憾的是其执行时机的设置似乎有些不甚合理 。设想有一个需要长期运行的函数 , 其中有无限循环语句,在循环体内不断的创建资源(或分配内存),并用defer语句确保释放 。由于函数一直运行没有返回,所有defer语句都得不到执行,循环过程中创建的大量短暂性资源一直积累着,得不到回收 。而且,系统为了存储defer列表还要额外占用资源,也是持续增加的 。这样下去 , 过不了多久,整个系统就要因为资源耗尽而崩溃 。像这类长期运行的函数,http.ListenAndServe()就是典型的例子 。在Go语言重点应用领域,可以说几乎每一个后台服务程序都必然有这么一类函数,往往还都是程序的核心部分 。如果程序员不小心在这些函数中使用了defer语句,可以说后患无穷 。如果语言设计者把defer的语义设定为在所属代码块结束时(而非函数返回时)执行,是不是更好一点呢?可是Go 1.0早已发布定型,为了保持向后兼容性,已经不可能改变了 。小心使用defer语句!一不小心就中招 。
前面说到 defer 还有其他的任务, 也就是 defer 中执行的 recover 可以捕获 panic 抛出的异常.
还有 defer 可以在 return 之后修改命名的返回值.
上面2个工作要求 defer 只能在函数退出时来执行.
楼主说的 defer 是类似 Swift2.0 中 defer 的行为, 但是 Swift2.0 中 defer 是没有前面2个特性的.
Go中的defer是以函数作用域作为触发的条件的, 是会导致楼主说的在 for 中执行的错误用法(哪个语言没有坑呢?).
不过 for 中 局部 defer 也是有办法的 (Go中的defer是以函数作用域):
for {
func(){
f, err := os.Open(...)
defer f.Close()
}()
}
在 for 中做一个闭包函数就可以了. 自己不会用不要怪别人没告诉你.
1.10 许多语言内置设施不支持用户定义的类型
for in、make、range、channel、map等都仅支持语言内置类型,不支持用户定义的类型(?) 。用户定义的类型没法支持for in循环,用户不能编写像make、range那样“参数类型和个数”甚至“返回值类型和个数”都可变的函数,不能编写像channel、map那样类似泛型的数据类型 。语言内置的那些东西,处处充斥着斧凿的痕迹 。这体现了语言设计的局限性、封闭性、不完善,可扩展性差,像是新手作品——且不论其设计者和实现者如何权威 。延伸阅读:Go语言是30年前的陈旧设计思想,用户定义的东西几乎都是二等公民(Tikhon Jelvis) 。

推荐阅读