Goで関数の名前を取得する方法は?


101

関数が与えられた場合、その名前を取得することは可能ですか?いう:

func foo() {
}

func GetFunctionName(i interface{}) string {
    // ...
}

func main() {
    // Will print "name: foo"
    fmt.Println("name:", GetFunctionName(foo))
}

runtime.FuncForPCが役立つと言われましたが、使用方法を理解できませんでした。

回答:


187

私自身の質問に答えて申し訳ありませんが、解決策を見つけました:

package main

import (
    "fmt"
    "reflect"
    "runtime"
)

func foo() {
}

func GetFunctionName(i interface{}) string {
    return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

func main() {
    // This will print "name: main.foo"
    fmt.Println("name:", GetFunctionName(foo))
}

2
これは機能しているように見えますが、ここでいくつかの注意が必要になる可能性があります。 vがnil関数値の場合に限り、結果がゼロになることが保証されます。」
jochen 2015

1
@jochenは「単一の関数ではない」ということは、誤検知(つまり、別の関数のポインター)を返す可能性があることを意味しますか?
themihai 2016

1
@themihai私は知らない、私が引用された文は、すべてのドキュメントであるgolang.org/pkg/reflect/#Value.Pointerはこれについて言います。しかし、引用は、異なる関数に対して同じポインタを取得できることを示しているようですね?この場合、GetFunctionName異なる関数に対して同じ名前を返す可能性がありますか?
jochen 2016

3
@jochenこれはクロージャに関係していると思います。同じ基本機能を持つ2つのクロージャを作成すると、閉じた値が異なっていても同等になります。
Alex Guerra

9

ファイル名と行番号がログに記録されるため、正確には何が必要かはわかりませんが、「runtime」パッケージを使用してTideland Common Go Library(http://tideland-cgl.googlecode.com/)でこれを行う方法を次に示します。

// Debug prints a debug information to the log with file and line.
func Debug(format string, a ...interface{}) {
    _, file, line, _ := runtime.Caller(1)
    info := fmt.Sprintf(format, a...)

    log.Printf("[cgl] debug %s:%d %v", file, line, info)

1
それは本当に助けにはなりません。コールスタックに関する情報を取得する必要はありませんが、特定の関数に関する情報を取得します。関数参照を指定して対応するPCを取得する方法を知っていれば(可能な場合)、質問に答えられると思います。
モーレ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.