我怎样才能得到延期功能的参考? [英] How can I get a reference to a defer function?

查看:74
本文介绍了我怎样才能得到延期功能的参考?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

本文指出:延迟声明将函数调用推送到清单。我想知道是否可以从我的程序中的其他位置访问该列表中的元素,然后调用它们?我可以多次调用它们吗?我假设我有一个引用推迟行为的函数(如果有帮助的话)。



所以,下面是我想要做的一个简短示例:

  func main {
doStuff = func(){
//打开数据库连接
//写入临时文件
//等等...

推迟func(){
//关闭数据库连接
//删除临时文件
//等等...
}()
}

AwesomeApplication(doStuff)
}

func AwesomeApplication(doStuff func() ){
//现在,我可以在`doStuff`中获得对延迟函数的引用吗?
//不,我不能只是在某处传递
//用`doStuff`来定义延迟函数。把这看作是我想要满足的好奇心,
//不是真正的用例。


解决方案

存储的 defer 调用完全是特定于实现的,所以您没有可靠的方法来访问此列表。 1 2 可以在中找到* g编译器系列的实现细节(尽管有点旧) Russ Cox的研究博客

递延函数与当前goroutine相关联( )和
(在* g系列的情况下)由当前堆栈指针标识。如果当前的堆栈框架匹配
堆栈框架存储在最顶端的 Defer 条目中,则调用此函数。



有了这些知识,使用cgo访问延迟函数列表就成为可能。
您需要知道的是


  • 当前堆栈指针

  • 函数的地址

  • 当前goroutine



然而,我不建议使用这个。
您描述的用例的一般解决方案是使用这样的函数:

  func setupRoutines ()(setUp,tearDown func()){
//存储数据库连接对象和这样的

返回func(){/ *连接数据库和这样的* /},func(){ / * close db and such * /}
}

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



小提琴与

一起玩

如果您真的有兴趣玩弄不安全和C,你可以使用下面的代码作为模板。



inspect / runtime.c:

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

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

FLUSH(& foo);

inspect / inspect.go

 包检查

导入不安全

func FirstDeferred()unsafe.Pointer

defer.go

  package main 

importdefer / inspect

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


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

这段代码(基于这个)可以访问当前的例程( g ),因此
推迟属性。因此,您应该能够访问指向函数
的指针,并将其包装到 FuncVal 中并返回。


This article states: "A defer statement pushes a function call onto a list." I'm wondering if I can access the elements in that list from another place in my program and then invoke them? Can I invoke them multiple times? I'm assuming that I have a reference to the function that has defer behavior (if that helps).

So, here's a short example of what I want to do:

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

解决方案

The 'list' where to defer calls are stored are fully implementation specific so you have no reliable way of getting to this list.1,2 The implementation details for the *g compiler family (albeit a bit older) can be found in Russ Cox' research blog.

Deferred functions are associated with the current goroutine (g->Defer) and (in case of *g family) identified by the current stack pointer. If the current stack frame matches the stack frame stored in the topmost Defer entry, this function is called.

With this knowledge it is possible to access the list of deferred functions using cgo. You need to know

  • the current stack pointer
  • the address of the function
  • the current goroutine

However, I don't recommend using this. A general solution for the use case you're describing would be to have a function like this:

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

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

In your code you could then share the tearDown function, which would be called using defer. This way you still have the bonus of having all your database connections and such local but you're able to share the initialization/disconnect functions.

Fiddle to play with

If you're really interested in playing around with unsafe and C, you can use the following code as a template.

inspect/runtime.c:

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

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

    FLUSH(&foo);
}

inspect/inspect.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 code (based on this) gives you access to the current go routine (g) and therefore the defer attribute of it. Therefore you should be able to access the pointer to the function and wrap it in a go FuncVal and return it.

这篇关于我怎样才能得到延期功能的参考?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆