Come ottenere il nome di una funzione in Go?


101

Data una funzione, è possibile ricavarne il nome? Dire:

func foo() {
}

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

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

Mi è stato detto che runtime.FuncForPC sarebbe stato d'aiuto, ma non sono riuscito a capire come usarlo.

Risposte:


188

Scusa per aver risposto alla mia domanda, ma ho trovato una soluzione:

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
Anche se questo sembra funzionare, potrebbe essere necessaria una certa attenzione qui: la documentazione per .Pointer () afferma "Se il tipo di v è Func, il puntatore restituito è un puntatore di codice sottostante, ma non necessariamente sufficiente per identificare una singola funzione in modo univoco. la garanzia è che il risultato è zero se e solo se v è un valore func nullo. "
jochen

1
@jochen "non una singola funzione" significa che potrebbe restituire falsi positivi (cioè il puntatore di una funzione diversa)?
themihai

1
@themihai Non lo so, la frase che ho citato è tutti i documenti su golang.org/pkg/reflect/#Value.Pointer dicono su questo. Ma la citazione sembra indicare che si potrebbe ottenere lo stesso puntatore per funzioni diverse, non è vero? E se questo è il caso, GetFunctionNamepotrebbe restituire lo stesso nome per funzioni diverse?
Jochen

3
@jochen Penso che questo abbia a che fare con le chiusure; se crei due chiusure che hanno la stessa funzione sottostante, saranno equivalenti anche se i valori su cui chiudono sono differenti.
Alex Guerra

9

Non esattamente quello che vuoi, perché registra il nome del file e il numero di riga, ma ecco come lo faccio nella mia libreria Tideland Common Go ( http://tideland-cgl.googlecode.com/ ) utilizzando il pacchetto "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
Questo non aiuta davvero. Non ho bisogno di ottenere informazioni sullo stack di chiamate, ma su una determinata funzione. Credo che la domanda avrebbe una risposta se sapessi come ottenere il pc corrispondente dato un riferimento a una funzione (se possibile).
moraes
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.