Dalam Go 1.6 dan lebih baru, Cgo mempunyai peraturan yang lebih ketat untuk lulus penunjuk kepada kod C. Ia tidak lagi dibenarkan untuk menghantar penuding Go yang menghala ke memori Go yang mengandungi sebarang penuding Go.
Kod Go berikut menunjukkan cara menghantar penuding fungsi kepada kod C:
<code class="go">import ( "fmt" "unsafe" ) /* extern void go_callback_int(void* foo, int p1); static inline void CallMyFunction(void* pfoo) { go_callback_int(pfoo, 5); } */ import "C" //export go_callback_int func go_callback_int(pfoo unsafe.Pointer, p1 C.int) { foo := *(*func(C.int))(pfoo) foo(p1) } func MyCallback(x C.int) { fmt.Println("callback with", x) } // we store it in a global variable so that the garbage collector // doesn't clean up the memory for any temporary variables created. var MyCallbackFunc = MyCallback func Example() { C.CallMyFunction(unsafe.Pointer(&MyCallbackFunc)) } func main() { Example() }</code>
Apabila menjalankan kod ini, ia menghasilkan ralat kerana memori Go yang ditunjuk oleh MyCallbackFunc mengandungi penuding fungsi Go (MyCallback).
Kepada menangani perkara ini, kita perlu mencari cara untuk menghantar penuding fungsi kepada kod C tanpa melanggar peraturan baharu.
Menggunakan ID Daripada Penunjuk
Satu pendekatan adalah untuk menyimpan penunjuk fungsi dalam struktur data yang disegerakkan dan menghantar ID kepada kod C dan bukannya penunjuk langsung. Dengan cara ini, kod C boleh menggunakan ID untuk mengakses penuding fungsi melalui struktur data.
Kod dengan Hantaran Penunjuk Fungsi Berasaskan ID
<code class="go">package gocallback import ( "fmt" "sync" ) /* extern void go_callback_int(int foo, int p1); static inline void CallMyFunction(int foo) { go_callback_int(foo, 5); } */ import "C" //export go_callback_int func go_callback_int(foo C.int, p1 C.int) { fn := lookup(int(foo)) fn(p1) } func MyCallback(x C.int) { fmt.Println("callback with", x) } func Example() { i := register(MyCallback) C.CallMyFunction(C.int(i)) unregister(i) } var mu sync.Mutex var index int var fns = make(map[int]func(C.int)) func register(fn func(C.int)) int { mu.Lock() defer mu.Unlock() index++ for fns[index] != nil { index++ } fns[index] = fn return index } func lookup(i int) func(C.int) { mu.Lock() defer mu.Unlock() return fns[i] } func unregister(i int) { mu.Lock() defer mu.Unlock() delete(fns, i) }</code>
Atas ialah kandungan terperinci Bagaimana untuk Menghantar Penunjuk Fungsi kepada Kod C Menggunakan Cgo dalam Go 1.6 dan Kemudian?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!