How can I get a snooze function link?

This article says: "The defer statement pushes a function call to a list." I am wondering if I can access the elements from this list from another place in my program and then call them? Can I call them several times? I assume that I have a link to a function that defers behavior (if that helps).

So here is a brief 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. } 
+4
source share
1 answer

The lists "list" in which defer is stored are defer , which are completely implementation-specific, so you have no reliable way to get this list . 1 , 2 Implementation details for the * g compiler family (although a bit older) can be found on the Russ Cox research blog .

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

With this knowledge, you can access the list of deferred functions using cgo. You must know

  • current stack pointer
  • function address
  • current goroutine

However, I do not recommend using this. The general solution for the use case that you are describing will have this function:

 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 can then share the tearDown function, which will be called using defer . Thus, you still have the bonus of having all the connections to the database and such local connections, but you are able to share the initialization / disconnection functions.

Try playing with

If you are really interested in playing 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 schema ( g ) and therefore the defer attribute. Therefore, you must have access to the function pointer and wrap it in go FuncVal and return it.

+11
source

Source: https://habr.com/ru/post/1499042/


All Articles