Як отримати назву функції в 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
Хоча це, здається, працює, тут може знадобитися деяка обережність: в документації для .Pointer () зазначено "Якщо v v Kind є Func, повернутий вказівник є основним вказівником коду, але не обов'язково достатньо, щоб однозначно визначити одну функцію. Єдине гарантія полягає в тому, що результат дорівнює нулю, якщо і лише тоді, коли v - значення нульового функціоналу. "
jochen

1
@jochen чи "не один функція" означає, що він може повернути помилкові позитиви (тобто вказівник іншої функції)?
themihai

1
@themihai Я не знаю, речення, яке я цитував, - це всі документи на golang.org/pkg/reflect/#Value.Pointer говорять про це. Але цитата, схоже, вказує на те, що можна отримати один і той же покажчик для різних функцій, чи не так? І якщо це так, GetFunctionNameможе повернути те саме ім’я для різних функцій?
jochen

3
@jochen Я думаю, що це стосується закриття; якщо створити два закриття, які мають однакову основну функцію, вони будуть еквівалентними, навіть якщо значення, які вони закривають, різні.
Алекс Герра

9

Не зовсім те, що ви хочете, тому що воно записує ім'я файлу та номер рядка, але ось як це зробити в моїй бібліотеці Tideland Common Go ( http://tideland-cgl.googlecode.com/ ) за допомогою пакету "runtime":

// 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
Це насправді не допомагає. Мені не потрібно отримувати інформацію про стек викликів, а про задану функцію. Я вважаю, що на це питання відповіли б, якби я знав, як отримати відповідний ПК із заданою функцією (якщо це можливо).
морени
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.