不,那里没有。你不能用你的函数做同样的事情。
您可以做的是使用函数类型的变量/值,您可以稍后/随时调用它,就好像它是一个函数一样。
例如:
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
}
Run Code Online (Sandbox Code Playgroud)
编辑:要获得您在评论中提到的功能:只需将函数调用及其参数包装在 a 中func(),然后使用 / 传递它。
例如:
func launch(f func()) {
fmt.Println("Before launch")
go func() {
defer fmt.Println("After completion")
f()
}()
}
Run Code Online (Sandbox Code Playgroud)
使用它:
func main() {
launch(func() {
fmt.Println("Hello, playground")
})
time.Sleep(time.Second)
}
Run Code Online (Sandbox Code Playgroud)
哪些输出(在Go Playground上试试):
Before launch
Hello, playground
After completion
Run Code Online (Sandbox Code Playgroud)
是的,这不是一个确切的解决方法。如果 params 可能会改变,你必须在调用之前制作它们的副本launch(),并在函数文字(闭包)中使用副本,如下例所示:
s := "Hello, playground"
s2 := s // make a copy
launch(func() {
fmt.Println(s2) // Use the copy
})
s = "changed"
Run Code Online (Sandbox Code Playgroud)
对于具体的函数类型,我们可以构造一个辅助函数,它为我们提供自动参数保存。此辅助函数必须具有相同的签名,并返回一个不带参数的函数。返回的函数是一个闭包,它使用参数调用原始函数。调用这个辅助函数的行为是保存参数的机制,所以用法和defer.
例如,帮手fmt.Println(s)是:
func wrapPrintln(s string) func() {
return func() {
fmt.Println(s)
}
}
Run Code Online (Sandbox Code Playgroud)
并使用它:
launch(wrapPrintln(s))
Run Code Online (Sandbox Code Playgroud)
具有 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))
Run Code Online (Sandbox Code Playgroud)
上面WrapPrintln()并WrapSum()包裹了一个具体的函数,它不能用于其他函数(被包裹的函数是“wired in”)。我们也可以将包装的函数作为参数:
func WrapFuncIntInt(f func(a, b int), a, b int) func() {
return func() {
f(a, b)
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以这样使用它:
launch(WrapFuncIntInt(Sum, a, b))
Run Code Online (Sandbox Code Playgroud)
在Go Playground上试试这个。
您可以使用反射来避免手动复制,但在这个解决方案中,我们实际上并没有调用函数,只是传递它。同样由于使用反射,它会更慢。另一个优点是这“感觉”是通用的(我们可能使用具有不同签名的函数),但我们失去了编译时的安全性。
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)
}()
}
Run Code Online (Sandbox Code Playgroud)
调用它的示例:
func main() {
i, s := 1, "Hello, playground"
launch(fmt.Printf, "%d %q\n", i, s)
i, s = 2, "changed"
time.Sleep(time.Second)
}
Run Code Online (Sandbox Code Playgroud)
哪些输出(在Go Playground上试试):
Before launch
1 "Hello, playground"
After completion
Run Code Online (Sandbox Code Playgroud)
我们可以使用一个例外。这是方法值。如果x具有静态类型T并且T的方法集包含该方法M,我们可以使用x.M(不调用它)。
表达式x.M是一个方法值,它保存了一个副本,x当表达式的结果(它是一个函数值)被调用时,它将被用作接收者。
例子:
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()
}()
}
Run Code Online (Sandbox Code Playgroud)
它输出相同。在Go Playground上试一试。
| 归档时间: |
|
| 查看次数: |
96 次 |
| 最近记录: |