如何使用 Go 的类型别名让自己的模型与 protobufs 一起工作?
Posted
技术标签:
【中文标题】如何使用 Go 的类型别名让自己的模型与 protobufs 一起工作?【英文标题】:How to use Go's type alias to make own models work with protobufs? 【发布时间】:2018-04-10 11:39:40 【问题描述】:我有一些 REST API,我的模型定义为 Go 结构。
type User struct
FirstName string
LastName string
然后我就有了获取数据的数据库方法。
GetUserByID(id int) (*User, error)
现在我想用 https://github.com/twitchtv/twirp 替换我的 REST API。
因此我开始在 .proto
文件中定义我的模型。
message User
string first_name = 2;
string last_name = 3;
现在我有两个User
类型。我们称它们为 native 和 proto 类型。
我还在我的.proto
文件中定义了一个服务,它将用户返回到前端。
service Users
rpc GetUser(Id) returns (User);
这会生成一个我必须填写的界面。
func (s *Server) GetUser(context.Context, id) (*User, error)
// i'd like to reuse my existing database methods
u, err := db.GetUserByID(id)
// handle error
// do more stuff
return u, nil
不幸的是,这不起作用。我的数据库返回 native 用户,但界面需要 proto 用户。
有没有简单的方法让它工作?也许使用type aliases
?
非常感谢!
【问题讨论】:
如果您不希望您的数据库包依赖于 protobuf 类型,您必须手动进行转换。如果类型足够相似,例如,您可以使用 json.Marshal 和 json.Unmarshal。您应该在问题中包含生成的类型,以便我们了解它们的不同之处。 而且类型别名绝对不是解决方案。别名不会创建新类型,只会为现有类型创建新名称。 【参考方案1】:解决问题的一种方法是手动进行转换。
type User struct
FirstName string
LastName string
type protoUser struct
firstName string
lastName string
func main()
u := db() // Retrieve a user from a mocked db
fmt.Println("Before:")
fmt.Printf("%#v\n", *u) // What db returns (*protoUser)
fmt.Println("After:")
fmt.Printf("%#v\n", u.AsUser()) // What conversion returns (User)
// Mocked db that returns pointer to protoUser
func db() *protoUser
pu := protoUser"John", "Dough"
return &pu
// Conversion method (converts protoUser into a User)
func (pu *protoUser) AsUser() User
return Userpu.firstName, pu.lastName
关键部分是
protoUser
结构上的AsUser
方法。 在那里,我们只需编写自定义逻辑,将protoUser
转换为我们想要使用的User
类型。
Working Example
【讨论】:
【参考方案2】:正如评论部分中提到的@Peter。
我见过一个使用自定义 Convert
函数的项目。它通过json.Unmarshal
将 Protobuf 转换为本地结构,不确定性能如何,但这是一种方法。
预览代码 PLAYGROUND
// Convert converts the in struct to out struct via `json.Unmarshal`
func Convert(in interface, out interface) error
j, err := json.Marshal(in)
if err != nil
return err
err = json.Unmarshal(j, &out)
if err != nil
return err
return nil
func main()
// Converts the protobuf struct to local struct via json.Unmarshal
var localUser User
if err := convert(protoUser, &localUser); err != nil
panic(err)
输出
Before:
main.ProtoUserFirstName:"John", LastName:"Dough"
After:
main.UserFirstName:"John", LastName:"Dough"
Program exited.
【讨论】:
以上是关于如何使用 Go 的类型别名让自己的模型与 protobufs 一起工作?的主要内容,如果未能解决你的问题,请参考以下文章