【发布时间】:2021-11-26 01:27:59
【问题描述】:
我正在尝试为我正在编写的 HTTP 处理程序自动创建命名记录器,并在其中传递了一个函数(指针)。
我正在使用this question 中提到的代码来获取函数的名称:
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()) 更好地获取函数的合格路径?
如果答案是否定的,有没有办法使用 runtime 或 reflect 获取当前 Go 模块名称,以便我可以将 runtime.FuncForPC 的输出转换为我需要的?
再一次,我得到如下值:
github.com/naftulikay/golang-webapp/experiments/functionname/long.HandlerAgithub.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path.HandlerBgithub.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path.HandlerC
我想获得如下值:
long.HandlerAlong.nested.path.HandlerBlong.nested.path.HandlerC
编辑: 看来 Go 没有模块的运行时表示,这没关系,如果我可以在编译时这样做,那也很好。我已经看过 codegen 文档,但我很难弄清楚如何编写可以从 go generate 使用的自定义 codegen。
【问题讨论】:
-
@gopher 有没有办法在构建时进行代码生成以解析
go.mod并将结果嵌入到我的程序中? -
我非常确定您需要“然后用字符串替换字符串。替换为 / 。”因为对于大多数 Go 开发人员来说,这看起来是非常错误的。这就是像 Java 这样的语言组织包的方式,但 不是 Go 组织它们的方式。 Go 使用斜线。因此,除非您有理由需要将它们用点分隔,否则您应该真正考虑让它们像往常一样以斜线分隔。
-
@Adrian 我正在为我的各种路线生成记录器名称,例如
app.routes.login.LoginHandler。斜线似乎有效,但斜线和圆点的混合让我感到困惑。我不需要文件名或行,只需要从函数指针中提取该值。 -
这很公平,这是您的设计决定,我只是想建议您谨慎,因为您似乎感到困惑的是过去使用 Go 的开发人员的正常情况(反之亦然)。 YMMV。
-
@gopher 没有吗?
debug.ReadBuildInfo()呢?
标签: go reflection