函數地址是指向函數代碼的指針,可以使用 unsafe.pointer 獲取。函數地址可傳遞給其他函數,例如打印函數名或按函數排序。它還允許使用函數指針類型斷言來檢查實現特定接口的函數。
深入理解 Go 函數地址的奧秘
引言
在 Go 中,函數地址是一個有價值的工具。它允許我們以引用的方式傳遞函數,從而賦予了代碼更大的靈活性。本篇文章將深入剖析函數地址的內部機制,并通過實戰案例展示其應用。
函數地址本質
函數地址本質上是一個指針,它指向函數在內存中的代碼段。與任何其他指針類似,它采用 *T
的形式,其中 T
是函數類型。
獲取函數地址
在 Go 中,可以使用 unsafe.Pointer
包中的 Pointer
函數獲取函數地址:
import "unsafe" func getFuncAddr(f func()) uintptr { return uintptr(unsafe.Pointer(&f)) }
登錄后復制
getFuncAddr
函數接收一個函數作為參數并返回其地址。
傳遞函數地址
函數地址可以作為參數傳遞給其他函數。例如,考慮一個打印函數名的函數:
import "fmt" func printFuncName(f func()) { fmt.Println(runtime.FuncForPC(getFuncAddr(f)).Name()) }
登錄后復制
printFuncName
接收一個函數并打印其名稱。runtime.FuncForPC
函數將函數地址轉換為其對應的 *Func
值,從而允許我們訪問函數的元數據。
實戰案例
排序切片:
我們可以使用函數地址對切片元素進行基于函數的排序:
func sortByFunc(nums []int, compare func(a, b int) int) { sort.Slice(nums, func(i, j int) bool { return compare(nums[i], nums[j]) < 0 }) } func main() { nums := []int{5, 2, 8, 1, 9} sortByFunc(nums, func(a, b int) int { return a - b }) fmt.Println(nums) // 輸出: [1 2 5 8 9] }
登錄后復制
在這個示例中,sortByFunc
接受一個切片和一個比較函數,然后使用 sort.Slice
根據比較函數對切片進行排序。
函數指針類型斷言:
函數指針類型斷言允許我們檢查函數指針是否實現了特定的接口:
import "fmt" type Stringer interface { String() string } func isStringer(f interface{}) bool { _, ok := f.(func() string) return ok } func main() { fmt.Println(isStringer(func() string { return "Hello" })) // true fmt.Println(isStringer(func() int { return 1 })) // false }
登錄后復制
isStringer
函數檢查給定接口值是否實現了 Stringer
接口。它使用類型斷言來確定接口值是否指向實現 String()
方法的函數。