Golang中将AST转换为代码时注释位置错乱问题
Golang中将AST转换为代码时注释位置错乱问题 当我将AST转换回Go程序时,原始Go程序中的所有注释都跑到了最后:
这是测试文件:test.go
package main
import "fmt"
func main() {
// comment here
if true{
fmt.Println("needs to be treated")
} else {
fmt.Println("you done it")
}
}
这是我得到的输出:output.go
package main
import "fmt"
func main() {
if true {
fmt.Println("needs to be treated")
} else {
fmt.Println("you done it")
}
}
// comment here
这是我的代码:main.go
package main
import (
"bytes"
"fmt"
"go/format"
"go/parser"
"go/token"
"log"
)
func main() {
fs := token.NewFileSet()
f, err := parser.ParseFile(fs, "test.go", nil, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
fset := token.NewFileSet()
var buf bytes.Buffer
err = format.Node(&buf, fset, f)
if err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
}
要运行此代码,只需在终端中执行:go run ./main.go > output.go。
执行后,为什么注释会跑到下面去?Go中是否有其他格式化函数不会这样做? 如果我查看test.go,我发现格式化函数读取的是AST文件中位于最后的注释部分。因此注释被放到了下面。 那么,有人能建议Go中是否有其他格式化函数可以将注释放在正确的位置吗?
更多关于Golang中将AST转换为代码时注释位置错乱问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
更多关于Golang中将AST转换为代码时注释位置错乱问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,处理AST时保留注释位置需要使用正确的配置和API。问题在于format.Node函数默认不会处理注释位置,需要使用go/format包的Source函数配合parser.ParseComments模式。
以下是修正后的代码:
package main
import (
"fmt"
"go/format"
"go/parser"
"go/token"
"log"
"os"
)
func main() {
// 读取源文件
src, err := os.ReadFile("test.go")
if err != nil {
log.Fatal(err)
}
// 解析文件并保留注释
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "test.go", src, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
// 使用format.Source处理,它会保留注释位置
formatted, err := format.Source(src)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(formatted))
}
或者,如果你需要操作AST后再格式化,应该这样做:
package main
import (
"bytes"
"fmt"
"go/format"
"go/parser"
"go/token"
"log"
)
func main() {
// 创建文件集
fset := token.NewFileSet()
// 解析文件并保留注释
f, err := parser.ParseFile(fset, "test.go", nil, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
// 这里可以对AST进行操作
// 例如修改函数、添加语句等
// 使用bytes.Buffer和format.Node,但需要正确的文件集
var buf bytes.Buffer
if err := format.Node(&buf, fset, f); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
}
关键点:
- 使用
parser.ParseFile时必须包含parser.ParseComments标志 format.Node需要传入正确的fset(包含位置信息的文件集)- 如果只是格式化源代码而不修改AST,使用
format.Source更简单
对于你的测试文件,修正后的代码会输出:
package main
import "fmt"
func main() {
// comment here
if true {
fmt.Println("needs to be treated")
} else {
fmt.Println("you done it")
}
}
注释会保持在原来的位置。

