当前位置: 首页 > 面试题库 >

去破坏者?

司马宏茂
2023-03-14
问题内容

我知道Go中没有析构函数,因为从技术上讲没有类。这样,我initClass用来执行与构造函数相同的功能。但是,有没有办法在终止的情况下创建某些东西来模仿析构函数,例如使用关闭文件?现在,我只是打电话给我defer deinitClass,但这有点荒唐,我认为设计很差。正确的方法是什么?


问题答案:

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



 类似资料:
  • 问题内容: 我有一个用Restify和Mongoose在node.js中构建的REST服务,以及一个mongoDB,它的集合包含大约30.000个常规大小的文档。我的节点服务通过pmx和pm2运行。 昨天,节点突然开始通过消息“ MongoError:拓扑已被破坏”消除错误,仅此而已。我不知道这是什么意思,可能触发了什么。谷歌搜索时也没有太多发现。所以我想在这里问。 今天重新启动了节点服务后,错误

  • 我想为我的移动应用程序添加背景,但当我使用“this.props.children”时,eslint说我“必须使用解构道具分配”。为什么我可以分解这些道具? 这是我的密码, 当我使用这个代码时 当我使用这个代码时, 提前感谢您的帮助!

  • 在实际应用中,destroy方法的可能示例是什么?为什么一个正在运行的应用程序想要销毁它的bean?如果bean是由spring容器(比如ContextLoaderListener)为web应用程序创建的,那么如何重新创建这些bean,因为容器已经启动了。有没有办法在不重启应用服务器的情况下重启spring IoC容器?

  • 问题内容: 无论如何,Java中是否有删除数据(例如,变量值,对象)并确保不能从内存中恢复数据的方法?在Java中分配变量是否会从内存中删除值?有任何想法吗?适用于其他语言的答案也是可以接受的。 问题答案: 由于虚拟内存的奇妙,几乎不可能以完全无法检索的方式从内存中删除某些内容。最好的选择是将值字段清零。然而: 这并不意味着该对象的旧(未清零)副本不会保留在未使用的交换页面上,该页面可能会在重新启

  • 问题内容: 我正在运行gulp 3.6.2,并具有从在线示例中设置的以下任务 每当我的CoffeeScript gulp手表出现错误时,手表就会停止-显然不是我想要的。 正如其他地方推荐的那样 但它似乎不起作用。 我究竟做错了什么? 响应@Aperçu的回答,我修改了方法并尝试了以下操作: 重新启动,然后在我的coffee文件中创建语法错误。相同的问题: 问题答案: 您的函数应如下所示: 我认为您

  • 1998年12月25日晚上(我的计算机时钟绝对准确),在进行完日常的一系列操作后,又准备对系统进行一下“挖潜”工作,我相信这是大多数PC 发烧友的共同爱好。主板的BIOS已经被升级过好几次了,而且目前我还没找到更新的BIOS升级数据文件,所以我把目光转向了主板附带光盘上的DMI(Desktop Management Interface,桌面管理接口)程序。DMI为用户提供了一个与系统硬件直接对话的