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

在Go中,变量何时将变得不可访问?

宗项禹
2023-03-14
问题内容

Go 1.7 beta 1今天早上发布,这是Go
1.7的发行说明草案
。新功能KeepAlive已添加到程序包中runtime。的文档runtime.KeepAlive给出了一个示例:

type File struct { d int }
d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0)
// ... do something if err != nil ...
p := &FILE{d}
runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) })
var buf [10]byte
n, err := syscall.Read(p.d, buf[:])
// Ensure p is not finalized until Read returns.
runtime.KeepAlive(p)
// No more uses of p after this point.

的文档runtime.SetFinalizer还给出了以下解释runtime.KeepAlive

例如,如果p指向包含文件描述符d的结构,并且p具有关闭该文件描述符的终结器,并且函数中对p的最后使用是对syscall的调用。Write(pd,buf,size
),则一旦程序进入syscall.Write,p可能无法访问。终结器可能会在此时运行,关闭pd,导致syscall.Write失败,因为它正在写入关闭的文件描述符(或更糟的是,写入由不同的goroutine打开的完全不同的文件描述符)。为避免此问题,请在调用syscall.Write之后调用runtime.KeepAlive(p)。

让我感到困惑的是,该变量p还没有离开它的生存范围,为什么它不可达?这是否意味着如果在以下代码中仅使用变量,则无论变量是否在其生存范围内,都将无法访问该变量?


问题答案:

当运行时检测到 Go 代码无法到达再次引用该变量的位置时,变量将变得不可访问。

在您发布的示例中,a
syscall.Open()用于打开文件。返回的文件描述符(只是一个int值)被“包装”在struct。然后,将终结器附加到此结构值,以关闭文件描述符。现在,当此结构值变得不可访问时,其终结器可能随时运行,并且文件描述符的关闭/失效/重用可能会导致意外的行为或Read()系统调用执行中的错误。

在一次使用这种结构值的p围棋 代码时syscall.Read()被调用(和文件描述符p.d传递给它)。系统调用的实现将使用文件描述符后
开始syscall.Read(),它可以这样做,直到syscall.Read()回报。但是,文件描述符的这种使用与Go代码“无关”。

因此,p在执行系统调用期间不会使用struct值,并且系统调用会阻塞Go代码,直到返回为止。这意味着Go运行时p在执行过程中Read()Read()返回之前)或
什至在其实际执行开始之前 被标记为不可访问(因为p仅用于提供call的参数)Read()

因此,对runtime.KeepAlive():的调用由于在该调用
之后syscall.Read()并且它 引用
了变量p,因此不允许Go运行时pRead()返回之前将其标记为不可访问,因为在Read()调用之后。

请注意,您可以使用其他构造来“保持p活动”,例如_ = p返回它。runtime.KeepAlive()在后台没有任何神奇的事情,其实现是:

func KeepAlive(interface{}) {}

runtime.KeepAlive() 确实提供了更好的选择,因为:

  • 它清楚地记录了我们要保持p生存的状态(以防止Finalizer运行)。
  • 使用其他结构(例如)_ = p可能会被将来的编译器“优化”,但不会被runtime.KeepAlive()调用。


 类似资料:
  • 问题内容: 我有两个变量,范围是: 现在,由于我的应用程序的大小开始增加,因此我决定将网站的每个模块放入其自己的程序包中,就像子目录一样: 我该如何解决从其他软件包访问和全局变量的问题?这是错误的做法吗?我有一种感觉。 在这种情况下,我怎么会在声明自己的命名空间功能,所以我没有发疯具有固定其名称和所有的时间。 问题答案: 大写的变量名导出为其他包访问,因此并会工作。但是,一般不建议使用子包进行名称

  • 在Rust中学习迭代器时,我创建了以下结构来隐藏二维集合的实现: 和方法的目标是这个结构的用户不需要担心数据是以行主格式还是列主格式存储;迭代器将简单地以最有效的顺序提供元素。 然而,在使用这种数据结构时,我通常需要知道特定的行和列,以便获得一些外部数据: 但是一旦我尝试调用方法,我就会得到以下编译器错误: 什么是实现我在这里尝试的正确方法?我可以添加一个<code>set</code>方法,该方

  • 问题内容: 我想知道是否存在一种实现类似于map getter的功能的方法:它返回返回值作为第一个参数,(可选地分配)第二个值作为第二个参数。因此,我需要可以通过以下方式调用的函数: 问题答案: 不,它无法完成,唯一的选择是返回一个指针并检查它是否为nil。

  • 问题内容: 我有一些这样的代码: 而且我收到警告,因为使用in闭包是可变变量,所以可能会引起问题。 我该如何避免呢?我的意思是我如何将不可变变量发送给回调,因为这是一个for循环,并且我无法更改代码?换句话说,如何将参数传递给闭包? 问题答案: 您需要创建一个范围以使用自执行功能正确捕获。这是因为整个for循环是一个作用域,也就是说,每次循环都捕获相同的变量。因此,回调将以错误的id结尾,因为的值

  • 本文向大家介绍python不可变变量?相关面试题,主要包含被问及python不可变变量?时的应答技巧和注意事项,需要的朋友参考一下 不可变对象是指不可以被引用改变的对象,如字符串 #

  • Go是静态类型语言,变量是有明确类型的。编译器会检查函数调用中,变量类型的正确性。 使用var关键字来定义变量。 Go 的基本类型有: bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte // uint8 的别名 rune // int32 的别名 代表一个Unicode码 floa