函數地址是指向函數代碼的指針,可以使用 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() 方法的函數。






