Golang中如何使用go/packages包的"pattern"参数

Golang中如何使用go/packages包的"pattern"参数 对于熟悉 golang.org/x/tools/go/packages 包的人来说,有没有办法在 Load 函数中指定一个 pattern,以便捕获给定目录路径(例如 Go 项目的根目录)内的所有包?在阅读了该包的文档后,我未能找到以这种方式指定模式的方法。

文档确实解释了通配符字符串 “…”(我将其附加到当前工作目录),但将其附加到项目根目录后,没有包被进行类型检查。

以下代码是我当前的方法。其问题之一是,共享相同包名但不在同一目录下的文件(例如在不同目录中定义的 package main)会被视为独立的包:

	c := &packages.Config{
		Mode: packages.NeedName | packages.NeedTypesInfo | packages.NeedSyntax,
		Dir:  rootDir,
	}
	err := filepath.Walk(rootDir, func(path string, info os.FileInfo, e error) error {
		if info.IsDir() {
			pkgs, err := packages.Load(c, path)
			if err != nil {
				log.Panicln(err)
			}
			if pkgs != nil {
				for _, pkg := range pkgs {
					log.Println(pkg.Name)
				}
			}
. . .

产生了以下输出:

2022/04/18 22:17:55 
2022/04/18 22:17:55 
2022/04/18 22:17:55 main
2022/04/18 22:17:55 main
2022/04/18 22:17:56 mypkg
2022/04/18 22:17:56 resolver
2022/04/18 22:17:56 testpkg

空白的包名代表根目录(即 go-types)和一个与 IDE 相关的目录(即 go-types/.idea)。

以下是我的目录结构,仅供参考:

go-types/
   .idea/
      [IDE-related files]
   cmd/
      change/
         main.go
      main.go
   mpkg/
      src.go
   resolver/
     exported.go
     util.go
   testpkg/
      exported.go

任何帮助都将不胜感激!如果有任何不清楚的地方,请告诉我!


更多关于Golang中如何使用go/packages包的"pattern"参数的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你期望你的测试输出什么?

更多关于Golang中如何使用go/packages包的"pattern"参数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢回复!我想我可能已经找到了问题的解决方案。关于我预期的输出,经过进一步观察,我现在认为给定的输出应该是预期的行为。

我主要关心的是找到一个模式,这样我就不必通过 filepath.Walk(...) 来遍历文件树。在仔细查阅文档后,我发现使用通配符时,我缺少的只是一个末尾的斜杠(例如,使用 /path/to/working/dir/... 而不是 /path/to/working/dir...)。使用这个方法,我得到了以下输出:

2022/04/19 09:20:45 resolver
2022/04/19 09:20:45 main
2022/04/19 09:20:45 main
2022/04/19 09:20:45 testpkg
2022/04/19 09:20:45 mypkg

这基本上与我上面的输出相同,其中似乎不包含没有 Go 文件的目录。

我找到的正确使用该模式的示例来源:Go Modules Reference - The Go Programming Language

go/packages 中使用 pattern 参数时,可以通过 ./... 模式来加载项目根目录下的所有包。你的代码需要调整 packages.Load 的调用方式,而不是使用 filepath.Walk

以下是修正后的代码示例:

c := &packages.Config{
    Mode: packages.NeedName | packages.NeedTypesInfo | packages.NeedSyntax,
    Dir:  rootDir,
}

pkgs, err := packages.Load(c, "./...")
if err != nil {
    log.Fatal(err)
}

for _, pkg := range pkgs {
    if pkg.Name != "" {
        log.Println(pkg.Name, pkg.PkgPath)
    }
}

关键点:

  1. Dir 字段设置为项目根目录 rootDir
  2. packages.Load 的 pattern 参数使用 "./..."
  3. 这会递归加载 rootDir 目录及其所有子目录中的 Go 包

对于你的目录结构,这会正确加载:

  • cmd/change/main.go (package main)
  • cmd/main.go (package main)
  • mpkg/src.go (package mypkg)
  • resolver/ 中的文件 (package resolver)
  • testpkg/ 中的文件 (package testpkg)

注意:packages.Load 会自动处理包名相同但路径不同的情况(如不同目录的 package main),每个都会被识别为独立的包。空包名通常表示目录不是有效的 Go 包(如 .idea/ 目录),可以通过检查 pkg.Name != "" 来过滤掉。

回到顶部