Jennifer
Jennifer 是一个 Go 语言的代码生成器。
package main
import (
"fmt"
. "github.com/dave/jennifer/jen"
)
func main() {
f := NewFile("main")
f.Func().Id("main").Params().Block(
Qual("fmt", "Println").Call(Lit("Hello, world")),
)
fmt.Printf("%#v", f)
}
输出:
package main
import "fmt"
func main() {
fmt.Println("Hello, world")
}
安装
go get -u github.com/dave/jennifer/jen
需要帮助?
如果你遇到困难,有问题,想要代码审查,或只是想聊聊:我很乐意帮忙!随时可以开一个 issue,给我发邮件,或在你的 PR 中提到 @dave。
示例
Jennifer 有一套全面的示例 - 请查看 godoc 索引。以下是一些 Jennifer 在实际项目中使用的例子:
- genjen (它使用 data.go 中的数据生成了 Jennifer 的大部分代码)
- zerogen
- go-contentful-generator
渲染
对于测试,可以使用 fmt 包的 %#v 动词渲染 File 或 Statement。
c := Id("a").Call(Lit("b"))
fmt.Printf("%#v", c)
// 输出:
// a("b")
不建议在生产环境中使用这种方式,因为任何错误都会导致 panic。对于生产环境,推荐使用 File.Render 或 File.Save。
标识符
标识符 关键字 运算符 括号 圆括号 控制流 集合 字面量 注释 泛型 辅助函数 其他 文件
Id
Id 渲染一个标识符。
c := If(Id("i").Op("==").Id("j")).Block(
Return(Id("i")),
)
fmt.Printf("%#v", c)
// 输出:
// if i == j {
// return i
// }
Dot
Dot 渲染一个句点后跟一个标识符。用于字段和选择器。
c := Qual("a.b/c", "Foo").Call().Dot("Bar").Index(Lit(0)).Dot("Baz")
fmt.Printf("%#v", c)
// 输出:
// c.Foo().Bar[0].Baz
Qual
Qual 渲染一个限定标识符。
c := Qual("encoding/gob", "NewEncoder").Call()
fmt.Printf("%#v", c)
// 输出:
// gob.NewEncoder()
当与 File 一起使用时,会自动添加导入。如果路径与本地路径匹配,则省略包名。如果包名冲突,会自动重命名。
f := NewFilePath("a.b/c")
f.Func().Id("init").Params().Block(
Qual("a.b/c", "Foo").Call().Comment("本地包 - 省略包名。"),
Qual("d.e/f", "Bar").Call().Comment("自动添加导入。"),
Qual("g.h/f", "Baz").Call().Comment("冲突的包名会被重命名。"),
)
fmt.Printf("%#v", f)
// 输出:
// package c
//
// import (
// f "d.e/f"
// f1 "g.h/f"
// )
//
// func init() {
// Foo() // 本地包 - 省略包名。
// f.Bar() // 自动添加导入。
// f1.Baz() // 冲突的包名会被重命名。
// }
注意,无法可靠地根据任意包路径确定包名,所以会根据路径猜测一个合理的名称并添加为别名。所有标准库包的名称都是已知的,因此不需要别名。如果需要更多地控制别名,请参见 File.ImportName 或 File.ImportAlias。
List
List 渲染一个逗号分隔的列表。用于多返回值函数。
c := List(Id("a"), Err()).Op(":=").Id("b").Call()
fmt.Printf("%#v", c)
// 输出:
// a, err := b()
关键字
标识符 关键字 运算符 括号 圆括号 控制流 集合 字面量 注释 泛型 辅助函数 其他 文件
简单的关键字、预声明标识符和内置函数都是不言自明的:
构造 | 名称 |
---|---|
关键字 | Break, Chan, Const, Continue, Default, Defer, Else, Fallthrough, Func, Go, Goto, Range, Select, Type, Var |
函数 | Append, Cap, Clear, Close, Complex, Copy, Delete, Imag, Len, Make, Max, Min, New, Panic, Print, Println, Real, Recover |
类型 | Bool, Byte, Complex64, Complex128, Error, Float32, Float64, Int, Int8, Int16, Int32, Int64, Rune, String, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr |
常量 | True, False, Iota, Nil |
辅助函数 | Err |
内置函数接受一个参数列表并适当地渲染它们:
c := Id("a").Op("=").Append(Id("a"), Id("b").Op("..."))
fmt.Printf("%#v", c)
// 输出:
// a = append(a, b...)
If, For、Interface, Struct、Switch, Case、Return 和 Map 的特殊情况将在下面解释。
运算符
标识符 关键字 运算符 括号 圆括号 控制流 集合 字面量 注释 泛型 辅助函数 其他 文件
Op 渲染提供的运算符/标记。
c := Id("a").Op(":=").Id("b").Call()
fmt.Printf("%#v", c)
// 输出:
// a := b()
c := Id("a").Op("=").Op("*").Id("b")
fmt.Printf("%#v", c)
// 输出:
// a = *b
c := Id("a").Call(Id("b").Op("..."))
fmt.Printf("%#v", c)
// 输出:
// a(b...)
c := If(Parens(Id("a").Op("||").Id("b")).Op("&&").Id("c")).Block()
fmt.Printf("%#v", c)
// 输出:
// if (a || b) && c {
// }
大括号
标识符 关键字 运算符 大括号 小括号 流程控制 集合 字面量 注释 泛型 辅助函数 其他 文件
以下几种方法用于渲染大括号,总结如下:
名称 | 前缀 | 分隔符 | 示例 |
---|---|---|---|
Block | \n | func a() { ... } 或 if a { ... } | |
Interface | interface | \n | interface { ... } |
Struct | struct | \n | struct { ... } |
Values | , | []int{1, 2} 或 A{B: "c"} |
Block
Block 渲染由大括号括起来的语句列表。用于代码块。
c := Func().Id("foo").Params().String().Block(
Id("a").Op("=").Id("b"),
Id("b").Op("++"),
Return(Id("b")),
)
fmt.Printf("%#v", c)
// 输出:
// func foo() string {
// a = b
// b++
// return b
// }
c := If(Id("a").Op(">").Lit(10)).Block(
Id("a").Op("=").Id("a").Op("/").Lit(2),
)
fmt.Printf("%#v", c)
// 输出:
// if a > 10 {
// a = a / 2
// }
在 Case 或 Default 后直接使用时有一个特殊情况,此时会省略大括号。这允许在 switch 和 select 语句中使用。参见示例。
Interface, Struct
Interface 和 Struct 渲染关键字后跟由大括号括起来的语句列表。
c := Var().Id("a").Interface()
fmt.Printf("%#v", c)
// 输出:
// var a interface{}
c := Type().Id("a").Interface(
Id("b").Params().String(),
)
fmt.Printf("%#v", c)
// 输出:
// type a interface {
// b() string
// }
c := Id("c").Op(":=").Make(Chan().Struct())
fmt.Printf("%#v", c)
// 输出:
// c := make(chan struct{})
c := Type().Id("foo").Struct(
List(Id("x"), Id("y")).Int(),
Id("u").Float32(),
)
fmt.Printf("%#v", c)
// 输出:
// type foo struct {
// x, y int
// u float32
// }
小括号
标识符 关键字 运算符 大括号 小括号 流程控制 集合 字面量 注释 泛型 辅助函数 其他 文件
几种方法输出小括号,总结如下:
名称 | 前缀 | 分隔符 | 示例 |
---|---|---|---|
Call | , | fmt.Println(b, c) | |
Params | , | func (a *A) Foo(i int) { ... } | |
Defs | \n | const ( ... ) | |
Parens | []byte(s) 或 a / (b + c) | ||
Assert | . | s, ok := i.(string) |
Call
Call 渲染由小括号括起来的逗号分隔列表。用于函数调用。
c := Qual("fmt", "Printf").Call(
Lit("%#v: %T\n"),
Id("a"),
Id("b"),
)
fmt.Printf("%#v", c)
// 输出:
// fmt.Printf("%#v: %T\n", a, b)
Params
Params 渲染由小括号括起来的逗号分隔列表。用于函数参数和方法接收器。
c := Func().Params(
Id("a").Id("A"),
).Id("foo").Params(
Id("b"),
Id("c").String(),
).String().Block(
Return(Id("b").Op("+").Id("c")),
)
fmt.Printf("%#v", c)
// 输出:
// func (a A) foo(b, c string) string {
// return b + c
// }
Defs
Defs 渲染由小括号括起来的语句列表。用于定义列表。
c := Const().Defs(
Id("a").Op("=").Lit("a"),
Id("b").Op("=").Lit("b"),
)
fmt.Printf("%#v", c)
// 输出:
// const (
// a = "a"
// b = "b"
// )
Parens
Parens 在小括号中渲染单个项目。用于类型转换或指定求值顺序。
c := Id("b").Op(":=").Index().Byte().Parens(Id("s"))
fmt.Printf("%#v", c)
// 输出:
// b := []byte(s)
c := Id("a").Op("/").Parens(Id("b").Op("+").Id("c"))
fmt.Printf("%#v", c)
// 输出:
// a / (b + c)
Assert
Assert 渲染一个句点后跟由小括号括起来的单个项目。用于类型断言。
c := List(Id("b"), Id("ok")).Op(":=").Id("a").Assert(Bool())
fmt.Printf("%#v", c)
// 输出:
// b, ok := a.(bool)
流程控制
标识符 关键字 运算符 大括号 小括号 流程控制 集合 字面量 注释 泛型 辅助函数 其他 文件
If, For
If 和 For 渲染关键字后跟分号分隔的列表。
c := If(
Err().Op(":=").Id("a").Call(),
Err().Op("!=").Nil(),
).Block(
Return(Err()),
)
fmt.Printf("%#v", c)
// 输出:
// if err := a(); err != nil {
// return err
// }
c := For(
Id("i").Op(":=").Lit(0),
Id("i").Op("<").Lit(10),
Id("i").Op("++"),
).Block(
Qual("fmt", "Println").Call(Id("i")),
)
fmt.Printf("%#v", c)
// 输出:
// for i := 0; i < 10; i++ {
// fmt.Println(i)
// }
Switch, Select
Switch、Select、Case和Block用于构建switch或select语句:
c := Switch(Id("value").Dot("Kind").Call()).Block(
Case(Qual("reflect", "Float32"), Qual("reflect", "Float64")).Block(
Return(Lit("float")),
),
Case(Qual("reflect", "Bool")).Block(
Return(Lit("bool")),
),
Case(Qual("reflect", "Uintptr")).Block(
Fallthrough(),
),
Default().Block(
Return(Lit("none")),
),
)
fmt.Printf("%#v", c)
// 输出:
// switch value.Kind() {
// case reflect.Float32, reflect.Float64:
// return "float"
// case reflect.Bool:
// return "bool"
// case reflect.Uintptr:
// fallthrough
// default:
// return "none"
// }
Return
Return渲染关键字,后跟逗号分隔的列表。
c := Return(Id("a"), Id("b"))
fmt.Printf("%#v", c)
// 输出:
// return a, b
集合
标识符 关键字 运算符 大括号 小括号 控制流 集合 字面量 注释 泛型 辅助函数 其他 文件
Map
Map渲染关键字,后跟一个由方括号括起来的单个项目。用于map定义。
c := Id("a").Op(":=").Map(String()).String().Values()
fmt.Printf("%#v", c)
// 输出:
// a := map[string]string{}
Index
Index渲染由方括号括起来的冒号分隔列表。用于数组/切片索引和定义。
c := Var().Id("a").Index().String()
fmt.Printf("%#v", c)
// 输出:
// var a []string
c := Id("a").Op(":=").Id("b").Index(Lit(0), Lit(1))
fmt.Printf("%#v", c)
// 输出:
// a := b[0:1]
c := Id("a").Op(":=").Id("b").Index(Lit(1), Empty())
fmt.Printf("%#v", c)
// 输出:
// a := b[1:]
Values
Values渲染由大括号括起来的逗号分隔列表。用于切片或复合字面量。
c := Index().String().Values(Lit("a"), Lit("b"))
fmt.Printf("%#v", c)
// 输出:
// []string{"a", "b"}
Dict渲染为键/值对。与Values一起用于map或复合字面量。
c := Map(String()).String().Values(Dict{
Lit("a"): Lit("b"),
Lit("c"): Lit("d"),
})
fmt.Printf("%#v", c)
// 输出:
// map[string]string{
// "a": "b",
// "c": "d",
// }
c := Op("&").Id("Person").Values(Dict{
Id("Age"): Lit(1),
Id("Name"): Lit("a"),
})
fmt.Printf("%#v", c)
// 输出:
// &Person{
// Age: 1,
// Name: "a",
// }
DictFunc执行func(Dict)来生成值。
c := Id("a").Op(":=").Map(String()).String().Values(DictFunc(func(d Dict) {
d[Lit("a")] = Lit("b")
d[Lit("c")] = Lit("d")
}))
fmt.Printf("%#v", c)
// 输出:
// a := map[string]string{
// "a": "b",
// "c": "d",
// }
注意:渲染时项目按键排序,以确保生成的代码可重复。
字面量
标识符 关键字 运算符 大括号 小括号 控制流 集合 字面量 注释 泛型 辅助函数 其他 文件
Lit
Lit渲染字面量。Lit只支持内置类型(bool、string、int、complex128、float64、float32、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、uintptr和complex64)。 传递任何其他类型都会引发panic。
c := Id("a").Op(":=").Lit("a")
fmt.Printf("%#v", c)
// 输出:
// a := "a"
c := Id("a").Op(":=").Lit(1.5)
fmt.Printf("%#v", c)
// 输出:
// a := 1.5
LitFunc通过执行提供的函数来生成要渲染的值。
c := Id("a").Op(":=").LitFunc(func() interface{} { return 1 + 1 })
fmt.Printf("%#v", c)
// 输出:
// a := 2
对于默认常量类型(bool、int、float64、string、complex128),Lit 将渲染无类型常量。
代码 | 输出 |
---|---|
Lit(true) | true |
Lit(1) | 1 |
Lit(1.0) | 1.0 |
Lit("foo") | "foo" |
Lit(0 + 1i) | (0 + 1i) |
对于所有其他内置类型(float32、int8、int16、int32、int64、uint、uint8、 uint16、uint32、uint64、uintptr、complex64),Lit也会渲染类型。
代码 | 输出 |
---|---|
Lit(float32(1)) | float32(1) |
Lit(int16(1)) | int16(1) |
Lit(uint8(0x1)) | uint8(0x1) |
Lit(complex64(0 + 1i)) | complex64(0 + 1i) |
内置别名类型byte和rune需要特殊处理。LitRune和LitByte 渲染rune和byte字面量。
代码 | 输出 |
---|---|
LitRune('x') | 'x' |
LitByte(byte(0x1)) | byte(0x1) |
注释
标识符 关键字 运算符 大括号 小括号 控制流 集合 字面量 注释 泛型 辅助函数 杂项 文件
Comment
Comment 添加一条注释。如果提供的字符串包含换行符,注释将以多行样式格式化。
f := NewFile("a")
f.Comment("Foo 返回字符串 \"foo\"")
f.Func().Id("Foo").Params().String().Block(
Return(Lit("foo")).Comment("返回字符串 foo"),
)
fmt.Printf("%#v", f)
// 输出:
// package a
//
// // Foo 返回字符串 "foo"
// func Foo() string {
// return "foo" // 返回字符串 foo
// }
c := Comment("a\nb")
fmt.Printf("%#v", c)
// 输出:
// /*
// a
// b
// */
如果注释字符串以 "//" 或 "/*" 开头,自动格式化将被禁用,字符串将直接渲染。
c := Id("foo").Call(Comment("/* 内联 */")).Comment("//无空格")
fmt.Printf("%#v", c)
// 输出:
// foo( /* 内联 */ ) //无空格
Commentf
Commentf 使用格式字符串和参数列表添加注释。
name := "foo"
val := "bar"
c := Id(name).Op(":=").Lit(val).Commentf("%s 是字符串 \"%s\"", name, val)
fmt.Printf("%#v", c)
// 输出:
// foo := "bar" // foo 是字符串 "bar"
泛型
标识符 关键字 运算符 大括号 小括号 控制流 集合 字面量 注释 泛型 辅助函数 杂项 文件
希望随着 Go 1.18 引入泛型,生成代码的需求会减少。然而,为了完整性,我们现在支持泛型,包括 any
和 comparable
预声明标识符,以及 Types
和 Union
列表。要生成近似(~
)标记,请使用 Op("~")
。
Types
Types 渲染一个用方括号括起来的逗号分隔列表。用于类型参数和约束。
Union
Union 渲染一个用管道符分隔的列表。用于联合类型约束。
示例
c := Func().Id("Keys").Types(
Id("K").Comparable(),
Id("V").Any(),
).Params(
Id("m").Map(Id("K")).Id("V"),
).Index().Id("K").Block()
fmt.Printf("%#v", c)
// 输出:
// func Keys[K comparable, V any](m map[K]V) []K {}
c := Return(Id("Keys").Types(Int(), String()).Call(Id("m")))
fmt.Printf("%#v", c)
// 输出:
// return Keys[int, string](m)
c := Type().Id("PredeclaredSignedInteger").Interface(
Union(Int(), Int8(), Int16(), Int32(), Int64()),
)
fmt.Printf("%#v", c)
// 输出:
// type PredeclaredSignedInteger interface {
// int | int8 | int16 | int32 | int64
// }
c := Type().Id("AnyString").Interface(
Op("~").String(),
)
fmt.Printf("%#v", c)
// 输出:
// type AnyString interface {
// ~string
// }
辅助函数
标识符 关键字 运算符 大括号 小括号 控制流 集合 字面量 注释 泛型 辅助函数 杂项 文件
Func 方法
所有接受可变参数列表的构造都配对有 GroupFunc 函数,这些函数接受一个 func(*Group)。用于嵌入逻辑。
c := Id("numbers").Op(":=").Index().Int().ValuesFunc(func(g *Group) {
for i := 0; i <= 5; i++ {
g.Lit(i)
}
})
fmt.Printf("%#v", c)
// 输出:
// numbers := []int{0, 1, 2, 3, 4, 5}
increment := true
name := "a"
c := Func().Id("a").Params().BlockFunc(func(g *Group) {
g.Id(name).Op("=").Lit(1)
if increment {
g.Id(name).Op("++")
} else {
g.Id(name).Op("--")
}
})
fmt.Printf("%#v", c)
// 输出:
// func a() {
// a = 1
// a++
// }
Add
Add 将提供的项添加到语句中。
ptr := Op("*")
c := Id("a").Op("=").Add(ptr).Id("b")
fmt.Printf("%#v", c)
// 输出:
// a = *b
a := Id("a")
i := Int()
c := Var().Add(a, i)
fmt.Printf("%#v", c)
// 输出:
// var a int
Do
Do 使用语句作为参数调用提供的函数。用于嵌入逻辑。
f := func(name string, isMap bool) *Statement {
return Id(name).Op(":=").Do(func(s *Statement) {
if isMap {
s.Map(String()).String()
} else {
s.Index().String()
}
}).Values()
}
fmt.Printf("%#v\n%#v", f("a", true), f("b", false))
// 输出:
// a := map[string]string{}
// b := []string{}
杂项
标识符 关键字 运算符 大括号 小括号 控制流 集合 字面量 注释 泛型 辅助函数 杂项 文件
Tag
Tag 渲染一个结构体标签
c := Type().Id("foo").Struct(
Id("A").String().Tag(map[string]string{"json": "a"}),
Id("B").Int().Tag(map[string]string{"json": "b", "bar": "baz"}),
)
fmt.Printf("%#v", c)
// 输出:
// type foo struct {
// A string `json:"a"`
// B int `bar:"baz" json:"b"`
// }
注意:渲染时项目按键排序,以确保代码可重复。
Null
Null 添加一个空项。空项不渲染任何内容,在列表中也不会跟随分隔符。
在列表中,nil 将产生相同的效果。
c := Func().Id("foo").Params(
nil,
Id("s").String(),
Null(),
Id("i").Int(),
).Block()
fmt.Printf("%#v", c)
// 输出:
// func foo(s string, i int) {}
Empty
Empty 添加一个空项。空项不会渲染任何内容,但在列表中会跟随一个分隔符。
c := Id("a").Op(":=").Id("b").Index(Lit(1), Empty())
fmt.Printf("%#v", c)
// 输出:
// a := b[1:]
Line
Line 插入一个空行。
Clone
使用 *Statement 时要小心。考虑以下情况...
a := Id("a")
c := Block(
a.Call(),
a.Call(),
)
fmt.Printf("%#v", c)
// 输出:
// {
// a()()
// a()()
// }
Id("a") 返回一个 *Statement,Call() 方法会对其进行两次追加。为避免这种情况,使用 Clone。Clone 会复制 Statement,这样可以追加更多的标记而不影响原始语句。
a := Id("a")
c := Block(
a.Clone().Call(),
a.Clone().Call(),
)
fmt.Printf("%#v", c)
// 输出:
// {
// a()
// a()
// }
Cgo
cgo 的 "C" 伪包是一个特殊情况,它总是渲染时不带包别名。可以使用 Qual
、Anon
或提供前言来添加导入。前言可以通过 File.CgoPreamble
添加,其语义与 Comment 相同。如果提供了前言,导入会被分开,并在前言之后。
f := NewFile("a")
f.CgoPreamble(`#include <stdio.h>
#include <stdlib.h>
void myprint(char* s) {
printf("%s\n", s);
}
`)
f.Func().Id("init").Params().Block(
Id("cs").Op(":=").Qual("C", "CString").Call(Lit("Hello from stdio\n")),
Qual("C", "myprint").Call(Id("cs")),
Qual("C", "free").Call(Qual("unsafe", "Pointer").Parens(Id("cs"))),
)
fmt.Printf("%#v", f)
// 输出:
// package a
//
// import "unsafe"
//
// /*
// #include <stdio.h>
// #include <stdlib.h>
//
// void myprint(char* s) {
// printf("%s\n", s);
// }
// */
// import "C"
//
// func init() {
// cs := C.CString("Hello from stdio\n")
// C.myprint(cs)
// C.free(unsafe.Pointer(cs))
// }
File
标识符 关键字 操作符 花括号 圆括号 控制流 集合 字面量 注释 泛型 辅助函数 其他 文件
File 代表一个单独的源文件。包导入由 File 自动管理。
NewFile
NewFile 创建一个新文件,指定包名。
NewFilePath
NewFilePath 创建一个新文件,同时指定包路径 - 包名从路径中推断。
NewFilePathName
NewFilePathName 创建一个新文件,指定包路径和名称。
f := NewFilePathName("a.b/c", "main")
f.Func().Id("main").Params().Block(
Qual("a.b/c", "Foo").Call(),
)
fmt.Printf("%#v", f)
// 输出:
// package main
//
// func main() {
// Foo()
// }
Save
Save 渲染文件并保存到指定的文件名。
Render
Render 将文件渲染到提供的 writer。
f := NewFile("a")
f.Func().Id("main").Params().Block()
buf := &bytes.Buffer{}
err := f.Render(buf)
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(buf.String())
}
// 输出:
// package a
//
// func main() {}
Anon
Anon 添加一个匿名导入。
f := NewFile("c")
f.Anon("a")
f.Func().Id("init").Params().Block()
fmt.Printf("%#v", f)
// 输出:
// package c
//
// import _ "a"
//
// func init() {}
ImportName
ImportName 为路径提供包名。如果指定,别名将从导入块中省略。这是可选的。如果未指定,将根据路径使用一个合理的包名,并将其作为别名添加到导入块中。
f := NewFile("main")
// 包 a 应使用名称 "a"
f.ImportName("github.com/foo/a", "a")
// 包 b 在代码中未使用,因此不会被包含
f.ImportName("github.com/foo/b", "b")
f.Func().Id("main").Params().Block(
Qual("github.com/foo/a", "A").Call(),
)
fmt.Printf("%#v", f)
// 输出:
// package main
//
// import "github.com/foo/a"
//
// func main() {
// a.A()
// }
ImportNames
ImportNames 允许以映射的形式导入多个名称。使用 gennames 命令可以自动生成一个包含选定包名映射的 go 文件。
ImportAlias
ImportAlias 为包路径提供在导入块中应使用的别名。可以使用句点强制点导入。
f := NewFile("main")
// 包 a 应别名为 "b"
f.ImportAlias("github.com/foo/a", "b")
// 包 c 在代码中未使用,因此不会被包含
f.ImportAlias("github.com/foo/c", "c")
f.Func().Id("main").Params().Block(
Qual("github.com/foo/a", "A").Call(),
)
fmt.Printf("%#v", f)
// 输出:
// package main
//
// import b "github.com/foo/a"
//
// func main() {
// b.A()
// }
Comments
PackageComment 在文件顶部、包关键字上方添加注释。
HeaderComment 在文件顶部、任何包注释上方添加注释。在头部注释下方会渲染一个空行,确保头部注释不包含在包文档中。
CanonicalPath 向包子句添加规范导入路径注释。
f := NewFile("c")
f.CanonicalPath = "d.e/f"
f.HeaderComment("代码由...生成")
f.PackageComment("包 c 实现了...")
f.Func().Id("init").Params().Block()
fmt.Printf("%#v", f)
// 输出:
// // 代码由...生成
//
// // 包 c 实现了...
// package c // import "d.e/f"
//
// func init() {}
CgoPreamble 添加一个 cgo 前言注释,直接在 "C" 伪包导入之前渲染。
PackagePrefix
如果你担心生成的包别名与本地变量名冲突,可以在这里设置前缀。包 foo 变成 {prefix}_foo。
f := NewFile("a")
f.PackagePrefix = "pkg"
f.Func().Id("main").Params().Block(
Qual("b.c/d", "E").Call(),
)
fmt.Printf("%#v", f)
// 输出:
// package a
//
// import pkg_d "b.c/d"
//
// func main() {
// pkg_d.E()
// }
NoFormat
可以将NoFormat设置为true以禁用生成的源代码的格式化。当性能至关重要且不需要可读性高的代码时,这可能会很有用。