首页 > 解决方案 > 在 Go 中获取当前模块的名称

问题描述

我正在尝试为我正在编写的 HTTP 处理程序自动创建命名记录器,并在其中传递了一个函数(指针)。

我正在使用这个问题中提到的代码来获取函数的名称:

package utils

import (
    "reflect"
    "runtime"
)

func GetFunctionName(fn interface{}) string {
    value := reflect.ValueOf(fn)
    ptr := value.Pointer()
    ffp := runtime.FuncForPC(ptr)

    return ffp.Name()
}

我在我的main函数中使用它来尝试它:

package main

import (
    "github.com/naftulikay/golang-webapp/experiments/functionname/long"
    "github.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path"
    "github.com/naftulikay/golang-webapp/experiments/functionname/utils"
    "log"
)

type Empty struct{}

func main() {
    a := long.HandlerA
    b := path.HandlerB
    c := path.HandlerC

    log.Printf("long.HandlerA: %s", utils.GetFunctionName(a))
    log.Printf("long.nested.path.HandlerB: %s", utils.GetFunctionName(b))
    log.Printf("long.nested.path.HandlerC: %s", utils.GetFunctionName(c))
}

我看到这样的输出:

github.com/naftulikay/golang-webapp/experiments/functionname/long.HandlerA

这没关系,但我想要一个输出,例如long.HandlerA,long.nested.path.HandlerB等。

如果我能得到 Go 模块名称 ( github.com/naftulikay/golang-webapp/experiments/functionname),然后我可以使用strings.Replace删除模块名称到达long/nested/path.HandlerB,然后strings.Replace替换/.最终得到我想要的值,即long.nested.path.HandlerB.

runtime.FuncForPC(reflect.ValueOf(fn).Pointer())第一个问题是:我能比获得函数的合格路径做得更好吗?

如果答案是否定的,有没有办法使用runtimeor获取当前的 Go 模块名称,reflect以便我可以将输出runtime.FuncForPC转换为我需要的?

再一次,我得到如下值:

我想获得如下值:

编辑: Go 似乎没有模块的运行时表示,这没关系,如果我可以在编译时这样做也可以。我已经看过 codegen 文档,我很难弄清楚如何编写我自己的自定义 codegen 可以从go generate.

标签: goreflection

解决方案


模块信息包含在可执行二进制文件中,可以使用debug.ReadBuildInfo()函数获取(唯一的要求是必须使用模块支持构建可执行文件,但这是当前版本的默认设置,并且可能在未来版本中唯一) .

BuildInfo.Path是当前模块的路径。

假设您有以下go.mod文件:

module example.com/foo

读取构建信息的示例:

bi, ok := debug.ReadBuildInfo()
if !ok {
    log.Printf("Failed to read build info")
    return
}

fmt.Println(bi.Path)

这将输出(在Go Playground上尝试):

example.com/foo

请参阅相关:Golang - 如何从代码内部显示模块版本


推荐阅读