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

Go 如何获取对延迟函数的引用?,go,Go,声明:“一个延迟语句将一个函数调用推送到一个列表上。”我想知道是否可以从程序中的另一个位置访问该列表中的元素,然后调用它们?我可以多次调用它们吗?我假设我有一个对具有延迟行为的函数的引用(如果有帮助的话) 下面是我想做的一个简短示例: func main { doStuff = func() { // open database connections // write temporary files // etc...

声明:“一个延迟语句将一个函数调用推送到一个列表上。”我想知道是否可以从程序中的另一个位置访问该列表中的元素,然后调用它们?我可以多次调用它们吗?我假设我有一个对具有延迟行为的函数的引用(如果有帮助的话)

下面是我想做的一个简短示例:

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.
}

存储
延迟
调用的“列表”是完全特定于实现的,因此您没有可靠的方法访问此列表,,可以找到*g编译器系列的实现详细信息(尽管有点旧)

延迟函数与当前goroutine()和 (对于*g系列)由当前堆栈指针标识。如果当前堆栈帧匹配 存储在最顶端的
Defer
条目中的堆栈帧,调用此函数

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

  • 当前堆栈指针
  • 函数的地址
  • 当前的goroutine
但是,我不建议使用这个。 您所描述的用例的一般解决方案是具有如下功能:

func setupRoutines() (setUp, tearDown func()) {
    // store db connection object and such

    return func() { /* connect db and such */ }, func() { /* close db and such */ }
}
然后,您可以在代码中共享
tearDown
函数,该函数将使用
defer
调用。 通过这种方式,您仍然可以获得所有数据库连接和本地连接的好处,但是 能够共享初始化/断开连接功能

摆弄 如果您真的对使用
unsafe
和C感兴趣,可以使用以下代码作为模板

inspect/runtime.c:

// +build gc
#include <runtime.h>

void ·FirstDeferred(void* foo) {
    foo = g->defer->fn;

    FLUSH(&foo);
}
推迟

package main

import "defer/inspect"

func f(a, b int) {
    println("deferred f(", a, b, ")")
}

func main() {
    defer f(1, 2)
    println( inspect.FirstDeferred() )
}
此代码(基于)允许您访问当前的go例程(
g
),因此 它的
defer
属性。因此,您应该能够访问该函数的指针
然后用go
FuncVal
将其包装并返回。

感谢您的深入解释。我希望它会更简单,可能是一个标准的库函数。我想我知道这不会很好。可悲的是,标准库中没有这方面的内容。然而,我不认为这有什么好处,因为它可以很容易地使用闭包进行建模。如果你认为这对标准图书馆有好处,你可以开一张票。:)我认为我的用例不适合标准库。我同意关闭是一条路要走。谢谢你提供的信息。非常好的回答+1.
package main

import "defer/inspect"

func f(a, b int) {
    println("deferred f(", a, b, ")")
}

func main() {
    defer f(1, 2)
    println( inspect.FirstDeferred() )
}