Làm thế nào để lấy tên của một hàm trong Go?


101

Cho một hàm, có thể lấy tên của nó không? Nói:

func foo() {
}

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

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

Tôi đã được thông báo rằng runtime.FuncForPC sẽ hữu ích, nhưng tôi không hiểu cách sử dụng nó.

Câu trả lời:


187

Xin lỗi vì đã trả lời câu hỏi của riêng tôi, nhưng tôi đã tìm ra giải pháp:

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
Mặc dù điều này có vẻ hiệu quả, nhưng có thể cần một số lưu ý ở đây: tài liệu cho .Pointer () nêu rõ "Nếu loại của v là Func, con trỏ trả về là con trỏ mã cơ bản, nhưng không nhất thiết đủ để xác định một hàm duy nhất. đảm bảo rằng kết quả bằng 0 nếu và chỉ khi v là Giá trị nil func. "
jochen

1
@jochen không "không phải một hàm duy nhất" có nghĩa là nó có thể trả về giá trị dương sai (tức là con trỏ của một hàm khác)?
themihai

1
@themihai Tôi không biết, câu tôi trích dẫn là tất cả các tài liệu tại golang.org/pkg/reflect/#Value.Pointer nói về điều này. Nhưng câu trích dẫn dường như chỉ ra rằng người ta có thể lấy cùng một con trỏ cho các chức năng khác nhau, phải không? Và nếu đúng như vậy, GetFunctionNamecó thể trả về cùng một tên cho các hàm khác nhau không?
jochen

3
@jochen Tôi nghĩ điều này liên quan đến việc đóng cửa; nếu bạn tạo hai bao đóng có cùng chức năng cơ bản, chúng sẽ tương đương nhau ngay cả khi giá trị mà chúng đóng lại khác nhau.
Alex Guerra

9

Không chính xác những gì bạn muốn, vì nó ghi lại tên tệp và số dòng, nhưng đây là cách tôi thực hiện trong Thư viện Tideland Common Go của tôi ( http://tideland-cgl.googlecode.com/ ) bằng cách sử dụng gói "thời gian chạy":

// 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
Điều đó không thực sự giúp ích. Tôi không cần lấy thông tin về ngăn xếp cuộc gọi, nhưng về một hàm đã cho. Tôi tin rằng câu hỏi sẽ được trả lời nếu tôi biết cách lấy máy tính tương ứng cho một tham chiếu hàm (nếu có thể).
moraes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.