为了账号安全,请及时绑定邮箱和手机立即绑定

go:识别“标志重新定义”的包

go:识别“标志重新定义”的包

Go
慕标琳琳 2023-02-06 18:59:13
如果一个标志被重新定义,go 只会告诉标志被重新定义的地方之一。有没有办法确定另一个标志的定义位置?举个例子,看下面的程序。在此处foo.go,定义了第一个标志。假设我试图在 package 中添加一个具有相同名称的标志main,go panic 告诉我该标志已经定义(因为 packagefoo首先被初始化)并且我正在 package 中重新定义它main。这是一个简单的例子,但在一个大型代码库中,标志可以在导入的库中定义,很难找出标志是在哪里第一次定义的。有什么办法可以找出来吗?package mainimport (    "flag"    "play.ground/foo")func main() {    var tf string    flag.StringVar(&tf, "tf", "", "")    foo.Bar()}-- go.mod --module play.ground-- foo/foo.go --package fooimport (    "flag"    "fmt")func init() {    var tf string    flag.StringVar(&tf, "tf", "", "")}func Bar() {    fmt.Println("This function lives in an another file!")}恐慌:/tmpfs/play flag redefined: tfpanic: /tmpfs/play flag redefined: tfgoroutine 1 [running]:flag.(*FlagSet).Var(0xc0000960c0, {0x4c3148, 0xc0000980a0}, {0x4a2642, 0x2}, {0x0, 0x0})    /usr/local/go-faketime/src/flag/flag.go:980 +0x2f9flag.StringVar(...)    /usr/local/go-faketime/src/flag/flag.go:851main.main()    /tmp/sandbox3734065722/prog.go:11 +0x7dProgram exited.游乐场:https ://go.dev/play/p/jsmMcnEO2hy
查看完整描述

1 回答

?
红颜莎娜

TA贡献1842条经验 获得超13个赞

正如上面评论中所写,没有工具可以做到这一点。


但是您可以使用一个简单的技巧来找出答案。


你想注册一个标志,但你不能,因为它已经在其他地方(未知位置)注册过。


如果可以先注册,则报错时会报当前注册的地方。


怎么做?创建一个注册此标志的包:


package first


import "flag"


func init() {

    flag.String("tf", "", "")

}

然后像这样在你的包中首先导入这个包main:


package main


import _ "play.gorund/first"


import (

    "flag"


    "play.ground/foo"

)

会发生什么?首先执行包init(),first正确注册tf标志,然后foo将尝试再次执行该操作,失败并报告错误。


示例输出(在Go Playground上尝试):


/tmpfs/play flag redefined: tf

panic: /tmpfs/play flag redefined: tf


goroutine 1 [running]:

flag.(*FlagSet).Var(0xc000062180, {0x4c3188, 0xc0000142a0}, {0x4a2642, 0x2}, {0x0, 0x0})

    /usr/local/go-faketime/src/flag/flag.go:980 +0x2f9

flag.StringVar(...)

    /usr/local/go-faketime/src/flag/flag.go:851

play.ground/foo.init.0()

    /tmp/sandbox1464715048/foo/foo.go:10 +0x7d

如您所见,foo.go第 10 行注册了tf标志。任务完成。


笔记:


许多编辑器在保存时自动设置格式,这可能涉及重新排列/重新组合导入,因此您的play.ground/first导入可能会向下移动,而不是第一个。为避免这种情况,请勿使用自动格式化功能,或为此包选择一个在自动格式化后将首先保留的名称。


笔记2:


Spec: Package initialization声明了初始化包的要求和规则,并没有指定处理导入的顺序(唯一保证的是所有引用的包在使用之前都会被递归初始化)。这意味着尽管当前的编译器按照列出的方式处理它们,但您不能 100% 依赖它。还有一个问题,即使是main包也有多个源文件,以不同的顺序向编译器提供它们也可能会改变初始化顺序。该规范将此作为“建议”:


为了确保可重现的初始化行为,鼓励构建系统以词法文件名顺序向编译器呈现属于同一包的多个文件。


查看完整回答
反对 回复 2023-02-06
  • 1 回答
  • 0 关注
  • 214 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号