不,那里没有。你不能对你的函数做同样的事情。
go and defer由语言规范支持,并且规则由编译器强制执行。
您可以做的是使用函数类型的变量/值,您可以稍后/随时调用它,就像它是一个函数一样。
例如:
func myFunc() {
fmt.Println("hi")
}
func main() {
var f func()
f = myFunc
f() // This calls the function value stored in f: myFunc in this example
}
Edit:要具有您在评论中提到的功能:只需将函数调用及其参数包装在func()
,并使用/传递它。
例如:
func launch(f func()) {
fmt.Println("Before launch")
go func() {
defer fmt.Println("After completion")
f()
}()
}
使用它:
func main() {
launch(func() {
fmt.Println("Hello, playground")
})
time.Sleep(time.Second)
}
哪个输出(尝试一下去游乐场):
Before launch
Hello, playground
After completion
是的,这不是一个确切的解决方法。如果参数可能发生变化,您必须在调用之前复制它们launch()
,并在函数文字(闭包)中使用副本,如下例所示:
s := "Hello, playground"
s2 := s // make a copy
launch(func() {
fmt.Println(s2) // Use the copy
})
s = "changed"
模仿自动参数保存
对于具体的函数类型,我们可以构造一个辅助函数,它为我们提供自动参数保存。该辅助函数必须具有相同的签名,并返回一个不带参数的函数。返回的函数是一个闭包,它使用参数调用原始函数。调用该辅助函数的行为是保存参数的机制,因此用法与defer
.
例如,助手fmt.Println(s)
is:
func wrapPrintln(s string) func() {
return func() {
fmt.Println(s)
}
}
并使用它:
launch(wrapPrintln(s))
具有 2 的函数示例int
参数:
func Sum(a, b int) {
fmt.Println("Sum:", a+b)
}
func WrapSum(a, b int) func() {
return func() {
Sum(a, b)
}
}
launch(WrapSum(a, b))
以上WrapPrintln()
and WrapSum()
包装了一个具体的函数,并且它不能用于其他函数(包装的函数是“连接的”)。我们也可以将包装的函数作为参数:
func WrapFuncIntInt(f func(a, b int), a, b int) func() {
return func() {
f(a, b)
}
}
我们可以这样使用它:
launch(WrapFuncIntInt(Sum, a, b))
试试这个去游乐场.
使用反射来避免手动复制
您可以使用反射来避免手动复制,但在这个解决方案中,我们实际上并没有调用该函数,只是传递它。另外由于使用反射,速度会慢一些。另一个优点是,这“感觉”通用(我们可以使用具有不同签名的函数),但我们失去了编译时安全性。
func launch(f interface{}, params ...interface{}) {
fmt.Println("Before launch")
go func() {
defer fmt.Println("After completion")
pv := make([]reflect.Value, len(params))
for i, v := range params {
pv[i] = reflect.ValueOf(v)
}
reflect.ValueOf(f).Call(pv)
}()
}
调用它的示例:
func main() {
i, s := 1, "Hello, playground"
launch(fmt.Printf, "%d %q\n", i, s)
i, s = 2, "changed"
time.Sleep(time.Second)
}
哪个输出(尝试一下去游乐场):
Before launch
1 "Hello, playground"
After completion
可以利用自动参数保存的单一例外
我们可以使用一个例外。这是方法值. If x
具有静态类型T
and T
's 方法集包含方法M
,我们可以使用x.M
(不调用它)。
表达方式x.M
是一个方法值,它保存了一个副本x
当调用表达式的结果(它是一个函数值)时,它将用作接收器。
Example:
type myParams struct {
format string
i int
s string
}
func (mp myParams) Call() {
fmt.Printf(mp.format, mp.i, mp.s)
}
func main() {
p := myParams{format: "%d %q\n", i: 1, s: "Hello, playground"}
launch(p.Call) // p is saved here
p.i, p.s = 2, "changed"
time.Sleep(time.Second)
}
func launch(f func()) {
fmt.Println("Before launch")
go func() {
defer fmt.Println("After completion")
f()
}()
}
它输出相同。尝试一下去游乐场.