Taip Go untuk Panggilan Fungsi
Apabila menggunakan kata kunci seperti pergi dan tangguh, panggilan fungsi diperlukan sebagai parameter. Walau bagaimanapun, adakah terdapat jenis tertentu yang boleh digunakan dengan cara yang sama, terutamanya untuk mencipta fungsi yang mengharapkan panggilan fungsi (bukan sekadar fungsi itu sendiri) sebagai hujah?
Keterbatasan dan Penyelesaian
Go tidak menyediakan jenis yang membenarkan fungsi ini secara langsung. Sebaliknya, seseorang boleh menggunakan pembolehubah atau nilai jenis fungsi dan memanggilnya kemudian seolah-olah ia adalah fungsi. Contohnya:
<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>
Untuk mencapai kefungsian yang diingini yang disebut dalam ulasan, bungkus panggilan fungsi dan argumen dalam func() dan gunakan itu. Contohnya:
<code class="go">func launch(f func()) { fmt.Println("Before launch") go func() { defer fmt.Println("After completion") f() }() }</code>
Penggunaan:
<code class="go">func main() { launch(func() { fmt.Println("Hello, playground") }) time.Sleep(time.Second) }</code>
Output:
Before launch Hello, playground After completion
Kaedah ini tidak melibatkan penyelesaian langsung. Jika parameter berubah, buat salinan sebelum memanggil pelancaran() dan gunakan salinan dalam fungsi literal (penutupan).
Meniru Penjimatan Parameter Automatik
Untuk fungsi tertentu taip, cipta fungsi pembantu dengan tandatangan yang sama, mengembalikan fungsi tanpa parameter. Fungsi yang dikembalikan bertindak sebagai penutup, memanggil fungsi asal dengan parameter. Menggunakan fungsi pembantu dengan berkesan menyimpan parameter, meniru tingkah laku penangguhan:
<code class="go">func wrapPrintln(s string) func() { return func() { fmt.Println(s) } }</code>
Penggunaan:
<code class="go">launch(wrapPrintln(s))</code>
Menggunakan Refleksi
Refleksi boleh menghapuskan keperluan untuk salinan manual, tetapi pendekatan ini melibatkan menghantar fungsi sebagai parameter dan bukannya memanggilnya. Ia juga lebih perlahan disebabkan oleh pantulan overhed.
<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>
Contoh penggunaan:
<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>
Output:
Before launch 1 "Hello, playground" After completion
Pengecualian: Nilai Kaedah
Satu pengecualian di mana penjimatan parameter automatik boleh digunakan adalah dengan nilai kaedah. Apabila x mempunyai jenis statik T dan set kaedah T mengandungi kaedah M, x.M (tanpa memanggilnya) mewakili nilai kaedah yang menangkap salinan x sebagai penerima apabila hasil ungkapan (nilai fungsi) dipanggil.
Atas ialah kandungan terperinci Bolehkah Go secara langsung mewakili panggilan fungsi sebagai jenis untuk digunakan sebagai parameter?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!