翻译来源:http://golang.org/s/using-guru
Guru 是一个导航go 代码的编辑器集成工具
这篇文章将展示了我们怎么使用Guru。在开发golang项目的过程中我们希望我们的编辑器回答我们各种各样的问题。例如:
- 标识符(名字,对于变量、常量、函数、语句块)在哪里申明?
- 所有对此申明的引用在哪里?
- 此表达式的方法变量是什么?
- 这个包的api 是什么?
- 哪些具体类型实现此接口?
- 动态调用可能的调用者是什么?
- 方法可能的调用这是什么?
- 在此channel 上发送的值可能在哪里接收?
除了它带来了一些在任何ide中没有发现的高级静态分析功能,它还带来了很多重量级ide才能带给你的令人兴奋的效果。
GopherCon 2014 talk on the Go Guru (https://www.youtube.com/watch?v=ak97oH0D6fI).
国内的视频地址(http://www.tudou.com/programs/view/VQgpql8a8fk/)
<p>
Guru支持十几种查询。把你的光标(或者文本选择)放在变量名称上或者你感兴趣的表达式位置上,然后通过你的编辑器来执行guru命令查询。
根据你的编辑器来选择你是使用菜单还是命令行。对与大多数查询指令来说查询的结果都会缓存在编辑器中。请看下面视频截图。 - Setting Up
- Queries
- Name Queries
- what
- definition
- referres
- freevars
- Type Queries
- describe
- implements
- Call graph queries
- callees
- callers
- callstack
- Alias queries
- pointsto
- whicherrs
- peers
Setting up
下载和编译guru工具,然后插入到你的.PATH路径下
$ go get golang.org/x/tools/cmd/guru
$ go build golang.org/x/tools/cmd/guru
$ mv guru $(go env GOROOT)/bin (for example)
$ guru -help
Go source code guru.Usage: guru [flags] <mode> <position>...
对与许多guru查询来说,定义包的工作空间必须配置$GOPATH 环境变量。虽然guru是一个命令行工具,但是需要借助你的编辑器来执行。大多数guru查询的输出是一个诊断列表,每一个前缀都有源文件的名称,行号,和列号。和一般编辑的诊断输出类似。大多数编辑器可以在缓冲区中显示编辑输出,以便点击诊断可以在正确的位置打开相关的源文件。请参考对应编辑器文档以完成安装。
编辑器| 链接
-----|-----|-----
Sublime text|https://alvarolm.github.io/GoGuru 安装文档:http://www.jianshu.com/p/7785511097ef
Acme|https://github.com/davidrjenni/A <p>https://github.com/mjibson/aw
Atom.io |https://atom.io/packages/go-oracle (现在不可用)
Eclipse |https://github.com/GoClipse/goclipse
Emacs |https://github.com/dominikh/go-mode.el <p>https://github.com/golang/tools/blob/master/cmd/guru/go-guru.el
Vim |https://github.com/fatih/vim-go
Vscode|https://github.com/fatih/vim-go
如果你的编辑器没有出现在以上的列表中,请想法子为其提供帮助支持。大多数查询可以通过少量重用编辑器的现有机制来运行编译器的逻辑来支持。这个逻辑必须构造一个指定所需类型的查询和当前光标位置的命令,并将该命令的输出定向到编辑器缓冲区。
某些功能需要额外的编辑器特定逻辑。Guru可以分析修改的但未保存的编辑器缓冲区,但这需要编辑器将修改的缓冲区的内容提供给guru的标准输入。编辑器可以在每次光标移动时自动高亮与当前选择标识符相同的标识符。或者它可以直接跳到定义查询后的变量声明处。当提供-json标志时,Guru以JSON格式发出输出; 这使得编辑者更容易解析工具的输出。
Pointer分析范围:一些涉及到指针分析的查询,一种用于回答“该指针可能指向什么?”的问题的技术。对workspace中的所有包运行指针分析通常太消耗资源,因此这些查询需要一个限定区域的附加配置参数,分析该参数指定的范围的包集。将范围设置为您当前正在其上工作的应用程序(或者应用程序集,可能是客户端和服务器)。指针分析是一个整体程序分析,所以范围内唯一的包是main和测试包。范围通常被指定为一组用逗号分隔的包,或者像github.com/my/dir / ...这样的通配子树; 请查阅编辑器的具体文档,了解如何设置和更改范围。
Queries
Guru支持大于十几个查询,以下列出来help 信息
callees | 显示所选函数调用的可能目标 |
---|---|
callers | 显示所选功能的可能调用者 |
callstack | 显示从调用图从根目录到选定函数的路径 |
definition | 显示所选标识符的声明 |
describe | 描述所选择的语法:定义,方法等 |
freevars | 显示选择的自由变量 |
implements | 显示所选类型或方法的“实现”关系 |
peers | 显示对应于所选频道操作的发送/接收 |
pointsto | 显示所选指针可能指向的变量 |
referrers | 显示由所选标识符表示的所有引用 |
what | 显示有关所选语法节点的基本信息 |
whicherrs | 显示所选错误变量的可能值 |
我们将把这些查询分成四组相关的特性---名称,类型,调用图和别名---使用这个程序作为一个运行的例子:
Name queries
Names (标识符)相关的声明引用。 第一组Guru查询帮助您从引用导航到声明,然后再返回。
what
what查询尽可能快地定位当前源位置。 只要光标位置改变。用户不需要做什么操作,只要鼠标位置发生变化编辑器就会做出相应的反馈。它可用于高亮显示与当前屏幕截图相同的所有标识符,如本示例屏幕截图所示:
definition
定义查询查找所选标识符的声明。 在一些编辑器中,它可以将光标直接跳到该位置。
示例:在此vedio中,我们使用连续的定义查询来查找http.Request的URL字段,类型url.URL和类型url.Userinfo。
referrers
referrers查询查找对所选标识符的引用,扫描workspace中的所有相关的包。
示例:在此vedio中,我们使用referrers 查找对处理程序类型的所有引用,以及在整个工作区中对http.Request的所有引用。
freevars
freevars查询会使用枚举的方式来选择自由变量。 “自由变量”是一个技术术语,指的是在选择中被引用但未被定义的一组变量,或者简单的说,它的输入。如果您正在考虑是否将选择的语句重构为自己的函数,那么此信息很有用,因为自由变量是函数的必要参数。 当你想了解一个复杂的代码块的输入是什么时,即使你不打算改变它,它也是有用的。
<p>
为了使结果更有用,查询的输出与教科书定义的自由变量略有不同:
- 输出不报告在包级别定义的任何名称,因为它们不需要作为参数传递到函数;
- 对于每一个自由的结构体变量,
- 输出还报告对自由常量和类型的引用,即它报告所有自由名称,而不仅仅是变量
<p>
示例:在这个video中,一个关于fmt包的十几行的freevars查询显示所选的语句块取决于typeString,v和p的几个部分。 如果我们将它提取为一个单独的函数,我们可能会使其成为具有以下签名的* pp方法:
> func (p *pp) fmtBytesSharpV(typeString string, v []byte)
Type queries
此组查询解答有关表达式类型的问题。
describe
describe查询显示所选语法的各种属性:其语法种类,表达式的类型,常量表达式的值,大小,对齐方式,方法集和类型的接口,标识符的声明等.你可以描述几乎任何一段语法,Guru将打印所有有用的信息。包的描述(例如fmt.Println中的fmt)包括其所有导出的成员,它们的类型,方法和值(对于常量)。 如果描述了当前包(通过选择包声明包p),描述也包括非导出成。
示例:在这个video中,我们描述处理程序类型,表达式w.Header(),http.Request的URL字段,最后是日志包。
implements
implements查询显示由所选类型实现的接口,如果所选类型本身是接口,则显示实现它的具体类型集合。 对值进行的实现查询报告有关表达式类型的相同信息。 对方法的implements查询显示与之相关的抽象或具体方法集合。
示例:在此video中,我们列出了类型处理程序实现的接口,类型为http.ResponseWriter和值req.URL。
Call graph queries
此查询回答关于调用图的问题,即函数调用点和被调用函数之间的关系。 对于静态函数或方法调用,关系是显而易见的,但对于动态调用,大师必须使用指针分析。 因此,必须在使用这些查询之前配置作用域。
callees
被调用方查询显示所选功能调用站点的可能的调用目标。 光标或选择必须在函数调用表达式中; 选择不必是精确的。 此查询使用指针分析来建模动态函数调用的影响,因此它需要一个作用域。
示例:调用接口方法的调用程序查询w.Header()告诉我们,在此应用程序中,调用可能分派两个可能的具体方法,一个用于HTTP v1,另一个用于HTTP v2。
callers
调用者的查询显示包含选择的函数的可能调用者。 此查询使用指针分析来建模动态函数调用的影响,因此它需要一个作用域。
示例:尽管没有对handler.ServeHTTP方法的直接调用,调用查询显示它由HTTP服务器包动态调用(因为它是一个注册的处理程序)。
callstack
callstack查询显示从调用图的根到包含选择的函数的任意路径。 这可能有助于了解在给定程序中如何达到该函数。 此查询使用指针分析来建模动态函数调用的影响,因此它需要一个作用域。调用堆栈信息的精度和有用性变化很大,特别是如果调用路径包含更大程度的动态调用。 所选的调用栈可能是不可行的,也就是说,在任何实际执行期间永远不会发生。
示例:此video 显示对handler.ServeHTTP函数的callstack查询。 它通过HTTP服务器中的几个函数逐步向上遍历生成的调用堆栈的帧,然后到达主调中的ListenAndServe调用。
Alias queries
别名查询回答有关指针(以及其他引用类型,如切片,地图,函数和通道)及其指向的内容的问题。 与调用图查询类似,别名查询使用指针分析,因此必须在调用范围之前配置范围。
pointsto
pointsto查询显示指针可能指向的可能对象的集合。 它也适用于其他参考类型,如片,函数,地图和通道。 此查询使用指针分析,因此必须指定范围。
示例:在此video中,pointsto查询告诉我们,在此程序中,http.ResponseWriter w可能包含两个可能的动态类型:* http.http2responsewriter和* http.response。 此外,每个指针都指向一个由复合文字表达式(“complit”)创建的变量。 单击使我们到创建http.response变量的位置。
whicherrs
whicherrs查询报告在类型错误的值中可能出现的一组可能的常量,全局变量和具体类型。 当处理错误时,此信息可能是有用的,以确保所有重要的情况都得到处理。
示例:对http.ListenAndServe调用结果的whicherrs查询显示可能的错误是EINVAL(程序员错误),系统调用错误或网络错误。
peers
对等端查询显示所选择的发送或接收操作的信道操作数上的可能的发送/接收的集合; 选择必须是< - 令牌。 此查询使用指针分析,因此必须指定范围。
示例:在计数器函数中的发送语句上的对等方查询报告信道在主处理器中被分配并且在处理器.ServeHTTP方法中被接收。