関数アドレスは関数コードへのポインターであり、unsafe.Pointer を使用して取得できます。関数アドレスは、関数名の印刷や関数による並べ替えなど、他の関数に渡すことができます。また、関数ポインター型アサーションを使用して、特定のインターフェイスを実装する関数をチェックすることもできます。
Go 関数アドレスの謎を深く理解する
はじめに
Go では、関数アドレスは貴重なツールです。これにより関数を参照渡しできるようになり、コードの柔軟性が高まります。この記事では、関数アドレスの内部メカニズムを深く分析し、実際のケースを通じてその応用例を示します。
関数アドレスの本質
関数アドレスは本質的にポインタであり、メモリ内の関数のコード セグメントを指します。他のポインターと同様に、*T
の形式をとります。T
は関数の型です。
関数アドレスの取得
Go では、unsafe.Pointer
パッケージの Pointer
関数を使用して関数を取得できます。 address:
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()
メソッドを実装する関数を指しているかどうかを判断します。
以上がGolang関数アドレスの秘密を深く理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。