栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

去破坏者?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

去破坏者?

在Go生态系统中,存在一种处理包装了宝贵(和/或外部)资源的对象的惯用语:一种专门用于释放该资源的特殊方法,通常通过该机制进行 显式
调用

defer

这种特殊的方法通常称为

Close()
,并且对象的用户用完对象表示的资源后必须显式调用它。该
io
标准包中甚至有专门的接口,
io.Closer
,宣称单一的方法。在各种资源(例如TCP套接字,UDP端点和文件)上实现I
/ O的对象都满足
io.Closer
,并且期望
Close
在使用后被显式指定。

调用这种清除方法通常是通过一种

defer
机制进行的,该机制确保无论资源获取后执行的某些代码是否执行,该方法都将运行
panic()

您可能还会注意到,在Go中,没有隐式的“析构函数”可以使没有隐式的“构造函数”达到平衡。实际上,这与Go中没有“类”无关:语言设计人员实际上尽可能地避免了
魔术


请注意,Go解决此问题的方法 似乎 技术含量较低,但实际上,它是运行时具有垃圾收集功能的唯一可行解决方案。在具有对象但没有GC的语言(例如C
++)中,销毁对象是定义明确的操作,因为对象超出范围或

delete
在其内存块上调用时都会被销毁。在带有GC的运行时中,该对象将在将来通过GC扫描在大多数不确定的点上
被破坏 ,并且 可能根本不会被破坏。
因此,如果对象包装了一些宝贵的资源,则该资源可能根本不会被回收,正如@twotwotwo在其各自的答案中所充分解释的那样。

需要考虑的另一个有趣方面是Go的GC是完全并发的(与常规程序执行一样)。这意味着将要收集死对象的GC线程可能(通常将不是)在该对象处于活动状态时执行该对象代码的线程。反过来,这意味着如果Go类型可以具有析构函数,则程序员将需要确保析构函数执行的任何代码均与程序的其余部分正确同步-
如果对象的状态影响了其外部的某些数据结构。实际上,这可能会迫使程序员添加这种同步,即使该对象在正常操作中不需要它(大多数对象都属于此类)。然后想想那些外部数据结构在对象被破坏之前发生了什么情况
称为析构函数(GC以非确定性方式收集死对象)。换句话说,在将对象显式编码到程序流中时,控制对象的破坏(并据此进行推理)要容易得多:既用于指定必须销毁对象的时间,又可以保证销毁与销毁有关的正确顺序外部数据结构。

如果您熟悉.NET,它将以类似于Go的方式来处理资源清除:包装一些宝贵资源的对象必须实现该

IDisposable
接口,并且
Dispose()
必须通过该接口导出的方法处理完此类对象后,将显式调用它。C#通过该
using
语句为此用例提供了一些语法糖,使编译器可以
Dispose()
在对象超出所述语句声明的范围时安排对其进行调用。在Go中,您通常会
defer
调用清除方法。


还要多加注意。Go希望您非常认真地对待错误(与大多数主流编程语言不同,它们“只是抛出异常,并且不会对其他地方由于错误所导致的后果以及程序将处于何种状态”提出任何质疑),因此您可能考虑至少检查对清除方法的
某些 调用的错误返回。

一个很好的例子是

os.File
代表文件系统上文件类型的实例。有趣的是,由于合法原因,调用
Close()
打开的文件 可能会 失败,并且如果您正在
写入 该文件,则可能表明并非您 写入 该文件的所有数据实际上都已放入 文件系统中。
有关说明,请阅读
close(2)
手册中的“注意”部分。

换句话说,只是做类似的事情

fd, err := os.Open("foo.txt")defer fd.Close()

在99.9%的情况下,只读文件是可以的,但是对于打开的文件,您可能需要实施更多涉及到的错误检查以及一些处理它们的策略(仅报告,等待然后重试,询问然后-
也许重试或其他)。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/471167.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号