为了账号安全,请及时绑定邮箱和手机立即绑定

如何获得对延迟函数的引用?

如何获得对延迟函数的引用?

Go
12345678_0001 2021-06-16 01:13:19
这篇文章指出:“defer 语句将函数调用推送到列表中。” 我想知道我是否可以从程序中的另一个地方访问该列表中的元素,然后调用它们?我可以多次调用它们吗?我假设我有一个对具有延迟行为的函数的引用(如果有帮助)。所以,这是我想要做的一个简短的例子:func main {    doStuff = func() {        // open database connections        // write temporary files        // etc...        defer func() {            // close database connections            // delete temporary files            // etc...        }()    }    AwesomeApplication(doStuff)}func AwesomeApplication(doStuff func()) {    // Now, can I get a reference to the defer function within `doStuff`?    // No, I can't just define the defer function somewhere an pass it    // with `doStuff`.  Think of this as a curiosity I want to satisfy,    // not a real use case.}
查看完整描述

1 回答

?
HUH函数

TA贡献1836条经验 获得超4个赞

defer存储调用的“列表”是完全特定于实现的,因此您没有可靠的方法来获取此列表1 , 2 *g 编译器系列(虽然有点旧)的实现细节可以在 Russ Cox 的研究博客中找到

延迟函数与当前的 goroutine ( g->Defer)相关联,并且(在 *g 系列的情况下)由当前堆栈指针标识。如果当前堆栈帧与存储在最顶层Defer条目中的堆栈帧匹配,则调用此函数。

有了这些知识,可以使用 cgo 访问延迟函数列表。你得知道

  • 当前堆栈指针

  • 函数地址

  • 当前的协程

但是,我不建议使用它。您所描述的用例的一般解决方案是具有这样的功能:

func setupRoutines() (setUp, tearDown func()) {

    // store db connection object and such


    return func() { /* connect db and such */ }, func() { /* close db and such */ }

}

在您的代码中,您可以共享该tearDown函数,该函数将使用defer. 这样,您仍然可以拥有所有数据库连接和本地连接,但您可以共享初始化/断开连接功能。


小提琴演奏

如果你真的有兴趣玩转unsafeC,你可以使用下面的代码作为模板。


检查/运行时.c:


// +build gc

#include <runtime.h>


void ·FirstDeferred(void* foo) {

    foo = g->defer->fn;


    FLUSH(&foo);

}

检查/检查.go


package inspect


import "unsafe"


func FirstDeferred() unsafe.Pointer

defer.go


package main


import "defer/inspect"


func f(a, b int) {

    println("deferred f(", a, b, ")")

}


func main() {

    defer f(1, 2)

    println( inspect.FirstDeferred() )

}

此代码(基于this)使您可以访问当前的 go 例程 ( g) 以及defer它的属性。因此,您应该能够访问指向该函数的指针并将其包装在 go 中FuncVal并返回它。


查看完整回答
反对 回复 2021-06-28
  • 1 回答
  • 0 关注
  • 181 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信