Как получить имя функции в Go?

102

Можно ли получить имя для данной функции? Сказать:

func foo() {
}

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

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

Мне сказали, что runtime.FuncForPC поможет, но я не понял, как его использовать.

Мораес
источник

Ответы:

190

Простите за ответ на свой вопрос, но я нашел решение:

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's Kind - это Func, возвращаемый указатель является базовым указателем кода, но не обязательно достаточным для однозначной идентификации отдельной функции. Единственный гарантия заключается в том, что результат равен нулю тогда и только тогда, когда v имеет значение nil func. "
jochen
1
@jochen не означает, что «ни одна функция» может возвращать ложные срабатывания (то есть указатель другой функции)?
themihai 01
1
@themihai Я не знаю, процитированное мной предложение - это все документы на golang.org/pkg/reflect/#Value.Pointer, которые говорят об этом. Но цитата, похоже, указывает на то, что можно получить один и тот же указатель для разных функций, не так ли? И если это так, GetFunctionNameможет возвращать одно и то же имя для разных функций?
jochen
3
@jochen Я думаю, это связано с закрытием; если вы создадите два замыкания, которые имеют одну и ту же базовую функцию, они будут эквивалентны, даже если значения, которые они закрывают, различны.
Alex Guerra
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
На самом деле это не помогает. Мне нужно получать информацию не о стеке вызовов, а о данной функции. Я считаю, что на этот вопрос можно было бы ответить, если бы я знал, как получить на соответствующий компьютер ссылку на функцию (если это возможно).
Мораес