関数呼び出しの Go タイプ
go や defer などのキーワードを使用する場合、パラメーターとして関数呼び出しが必要です。しかし、特に引数として関数呼び出し (単に関数自体ではなく) を期待する関数を作成する場合に、同様の方法で使用できる特定の型はありますか?
制限事項と回避策
Go は、この機能を直接可能にする型を提供しません。代わりに、関数型の変数または値を使用し、それらを関数であるかのように後で呼び出すことができます。例:
<code class="go">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 }</code>
コメントで言及されている目的の機能を実現するには、関数呼び出しと引数を func() 内にラップし、それを利用します。例:
<code class="go">func launch(f func()) { fmt.Println("Before launch") go func() { defer fmt.Println("After completion") f() }() }</code>
使用法:
<code class="go">func main() { launch(func() { fmt.Println("Hello, playground") }) time.Sleep(time.Second) }</code>
出力:
Before launch Hello, playground After completion
このメソッドには直接的な回避策は含まれません。パラメータが変更された場合は、launch() を呼び出す前にコピーを作成し、そのコピーを関数リテラル (クロージャ) 内で使用します。
自動パラメータ保存の模倣
特定の関数の場合と入力し、同一のシグネチャを持つヘルパー関数を作成し、パラメーターのない関数を返します。返された関数はクロージャとして機能し、パラメータを指定して元の関数を呼び出します。ヘルパー関数を呼び出すと、パラメーターが効果的に保存され、defer の動作が模倣されます:
<code class="go">func wrapPrintln(s string) func() { return func() { fmt.Println(s) } }</code>
Usage:
<code class="go">launch(wrapPrintln(s))</code>
Using Reflection
Reflection手動コピーの必要性を排除できますが、このアプローチでは関数を呼び出すのではなくパラメーターとして渡す必要があります。また、リフレクションのオーバーヘッドにより遅くなります。
<code class="go">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) }() }</code>
使用例:
<code class="go">func main() { i, s := 1, "Hello, playground" launch(fmt.Printf, "%d %q\n", i, s) i, s = 2, "changed" time.Sleep(time.Second) }</code>
出力:
Before launch 1 "Hello, playground" After completion
例外: メソッド値
パラメータの自動保存を利用できる例外の 1 つは、メソッド値の場合です。 x が静的型 T を持ち、T のメソッド セットにメソッド M が含まれている場合、x.M (呼び出しなし) は、式の結果 (関数値) が呼び出されたときにレシーバーとして x のコピーをキャプチャするメソッド値を表します。
以上がGo は関数呼び出しをパラメーターとして使用する型として直接表現できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。