列出给定导入路径的所有导入类型。

huangapple go评论78阅读模式
英文:

List all imported types given an import path

问题

我正在尝试在运行时列出给定导入路径中的所有导入类型。示例代码:

package main

import (
	"fmt"
	"go/importer"
)

func main() {
    pkg, err := importer.Default().Import("github.com/aler9/goroslib/pkg/msgs/std_msgs") 
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	for _, declName := range pkg.Scope().Names() {
		fmt.Println(declName)
	}
}

这会导致错误:

错误:找不到导入:"github.com/aler9/goroslib/pkg/msgs/std_msgs"

是否可以用Golang实现我想要的功能?


注意:

我知道这篇文章:https://stackoverflow.com/questions/56259230/how-to-use-go-importer

通过使用pkg, err := importer.Default().Import("github.com/aler9/goroslib"),二进制文件会返回一些类型,但它们不是我想要的。

英文:

I am trying to list all imported types from a given import path at runtime. Sample code:

package main

import (
	"fmt"
	"go/importer"
)

func main() {
    pkg, err := importer.Default().Import("github.com/aler9/goroslib/pkg/msgs/std_msgs") 
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	for _, declName := range pkg.Scope().Names() {
		fmt.Println(declName)
	}
}

This results in error:

> error: can't find import: "github.com/aler9/goroslib/pkg/msgs/std_msgs"

It is possbile to achieve what I want with Golang?


Note:

I am aware of the post: https://stackoverflow.com/questions/56259230/how-to-use-go-importer

By using pkg, err := importer.Default().Import("github.com/aler9/goroslib") the binary returns a few types but they are not what I want.


答案1

得分: 4

我不知道如何使用go/importer来做这个,甚至不确定是否可能。

不过,你可以使用golang.org/x/tools/go/packages包来加载一个包的AST,然后遍历该树来打印出你找到的任何类型声明。

package main

import (
	"fmt"
	"go/ast"
	"go/token"
	"golang.org/x/tools/go/packages"
)

func main() {
	loadConfig := new(packages.Config)
	loadConfig.Mode = packages.NeedSyntax
	loadConfig.Fset = token.NewFileSet()
	pkgs, err := packages.Load(loadConfig, "encoding/json")
	if err != nil {
		panic(err)
	}

	for _, pkg := range pkgs {
		for _, syn := range pkg.Syntax {
			for _, dec := range syn.Decls {
				if gen, ok := dec.(*ast.GenDecl); ok && gen.Tok == token.TYPE {
					for _, spec := range gen.Specs {
						if ts, ok := spec.(*ast.TypeSpec); ok {
							fmt.Println(ts.Name)
						}
					}
				}
			}
		}
	}
}

注意1:上面的示例将打印出导出的类型和未导出的类型。如果你只想打印出导出的类型,你可以添加一个条件来检查ts.Name.IsExported

注意2:如果我没记错的话,你想要加载的包 必须 已经在你的模块缓存中,因为packages.Load不会通过网络下载它,如果它不在缓存中的话。

英文:

I don't know how to do it with go/importer, or even if it's possible.

However, you could, for example, use the golang.org/x/tools/go/packages package to load a package's AST and then traverse that tree to print out any type declarations you find.

package main

import (
	"fmt"
	"go/ast"
	"go/token"
	"golang.org/x/tools/go/packages"
)

func main() {
	loadConfig := new(packages.Config)
	loadConfig.Mode = packages.NeedSyntax
	loadConfig.Fset = token.NewFileSet()
	pkgs, err := packages.Load(loadConfig, "encoding/json")
	if err != nil {
		panic(err)
	}

	for _, pkg := range pkgs {
		for _, syn := range pkg.Syntax {
			for _, dec := range syn.Decls {
				if gen, ok := dec.(*ast.GenDecl); ok && gen.Tok == token.TYPE {
					for _, spec := range gen.Specs {
						if ts, ok := spec.(*ast.TypeSpec); ok {
							fmt.Println(ts.Name)
						}
					}
				}
			}
		}
	}
}

NOTE #1: The above example will print exported and unexported types. If you want to print exported only you can add an if condition to check for ts.Name.IsExported.

NOTE #2: The package you want to load, if I'm not mistaken, must already be in your module cache because packages.Load will not go over the network and download it if it's not there.

huangapple
  • 本文由 发表于 2021年8月16日 03:42:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/68794847.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定