迁移至Go版Google Protobuf v2后,如何禁用结构体内部字段生成?
问题解答
首先明确:没有办法禁用生成这些内部字段,它们是google.golang.org/protobuf v2运行时的核心组成部分,负责消息的状态跟踪、序列化大小缓存和未知字段的存储,是库实现懒加载、并发安全等特性的基础,强行禁用会导致protobuf功能完全失效。
针对你遇到的两个问题,正确的解决方式如下:
1. 解决值传递报错的问题
protobuf v2生成的消息结构体内部嵌套了sync.Mutex(在MessageState中),这类带锁的类型绝对不能按值传递——值拷贝会复制锁的状态,引发并发安全问题甚至死锁。
你需要修改代码中所有传递消息的逻辑:
- 函数参数、返回值改用消息指针类型,比如
func processSpec(spec *waf_rules.GlobalSpecType)而非func processSpec(spec waf_rules.GlobalSpecType) - 结构体字段、切片、映射中的消息元素,全部改用指针类型,比如
map[string]*waf_rules.GlobalSpecType而非map[string]waf_rules.GlobalSpecType - 创建消息实例时,始终用指针初始化:
spec := &waf_rules.GlobalSpecType{}或spec := new(waf_rules.GlobalSpecType)
2. 解决proto.Equal无法正常比较的问题
proto.Equal对v2消息完全兼容,但你必须传递消息指针进行比较,而非值。示例:
// 正确用法 if proto.Equal(&msg1, &msg2) { // ... } // 错误用法(会导致比较失效) if proto.Equal(msg1, msg2) { // ... }
如果是比较包含消息的映射或切片,确保容器里存的是消息指针,这样遍历比较时才能用proto.Equal正确对比每个元素。
另外,若需要拷贝消息,不要手动做值拷贝,要用proto.Clone方法,它会正确处理内部状态:
clonedSpec := proto.Clone(originalSpec).(*waf_rules.GlobalSpecType)
内容的提问来源于stack exchange,提问作者golang_programmer
相关产品推荐
相关产品推荐

