代码生成
实验性特性
代码生成在 Fory Go 中仍属于实验性能力。未来版本中,API 和行为都可能发生变化。对于大多数场景,基于反射的路径仍然是更稳定、也更推荐的方案。
Fory Go 为性能敏感路径提供可选的 AOT 代码生成能力,可以消除反射开销,并提升编译期类型安全。
为什么使用代码生成
| 维度 | 基于反射 | 代码生成 |
|---|---|---|
| 接入成本 | 零配置 | 需要 go generate |
| 性能 | 较好 | 更好(无反射) |
| 类型安全 | 运行时 | 编译期 |
| 维护成本 | 自动 | 需要重新生成 |
适合使用代码生成的场景:
- 需要极致性能
- 希望在编译期获得更强的类型校验
- 热路径对延迟非常敏感
适合继续使用反射的场景:
- 更看重简单接入
- 类型经常变化
- 需要动态类型能力
- 不希望增加代码生成链路
安装
安装 fory 代码生成器:
go install github.com/apache/fory/go/fory/cmd/fory@latest
GO111MODULE=on go get -u github.com/apache/fory/go/fory/cmd/fory
确保 $GOBIN 或 $GOPATH/bin 已加入 PATH。
基本用法
步骤 1:标注结构体
在需要生成序列化器的结构体上方添加 //fory:generate 注释:
package models
//fory:generate
type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
//fory:generate
type Order struct {
ID int64
Customer string
Total float64
}
步骤 2:添加 go generate 指令
为文件或包添加 go:generate 指令:
//go:generate fory -file models.go
如果希望对整个包生成:
//go:generate fory -pkg .
步骤 3:运行代码生成
go generate ./...
执行后会生成 models_fory_gen.go,其中包含对应的序列化器实现。
生成代码的结构
生成器通常会产出以下内容。
类型快照
用于在编译期检测结构体定义是否已变更:
// 生成时的 User 类型快照
type _User_expected struct {
ID int64
Name string
}
// 编译期校验:如果 User 结构已变化,这里会报错
var _ = func(x User) { _ = _User_expected(x) }
序列化器实现
使用强类型方法直接读写字段:
type User_ForyGenSerializer struct{}
func (User_ForyGenSerializer) WriteTyped(f *fory.Fory, buf *fory.ByteBuffer, v *User) error {
buf.WriteInt64(v.ID)
fory.WriteString(buf, v.Name)
return nil
}
func (User_ForyGenSerializer) ReadTyped(f *fory.Fory, buf *fory.ByteBuffer, v *User) error {
v.ID = buf.ReadInt64()
v.Name = fory.ReadString(buf)
return nil
}
自动注册
生成代码会在 init() 中自动注册序列化器:
func init() {
fory.RegisterGenSerializer(User{}, User_ForyGenSerializer{})
}