当我从协议缓冲区文件生成go代码时,我注意到每个生成的结构都实现了Message接口,https://github.com/golang/protobuf/blob/master/proto/lib.go#L277
有关生成的代码示例,请参阅https://github.com/google/go-genproto/blob/master/googleapis/rpc/status/status.pb.go#L97
显然,Message接口,String()和Reset()上的其他方法有一个明显的目的,具体的实现示例清楚地说明了这一点。但是,我不明白ProtoMessage()方法的目的。该方法不带参数,也不返回任何参数,为什么会出现?
引自官方文件:Protocol Buffers: Go Generated Code:
给出一个简单的消息声明:
message Foo {}
协议缓冲区编译器生成一个名为
Foo
的结构。*Foo
实现了Message界面。有关详细信息,请参阅内联注释。type Foo struct { } // Reset sets the proto's state to default values. func (m *Foo) Reset() { *m = Foo{} } // String returns a string representation of the proto. func (m *Foo) String() string { return proto.CompactTextString(m) } // ProtoMessage acts as a tag to make sure no one accidentally implements the // proto.Message interface. func (*Foo) ProtoMessage() {}
请注意,所有这些成员始终存在;
optimize_for
选项不会影响Go代码生成器的输出。
这是Go官方FAQ: How can I guarantee my type satisfies an interface?中描述的(类似)技术
如果希望接口的用户明确声明它们实现它,则可以向接口的方法集添加具有描述性名称的方法。例如:
type Fooer interface { Foo() ImplementsFooer() }
然后一个类型必须将
ImplementsFooer
方法实现为Fooer
,清楚地记录事实并在godoc的输出中宣布它。type Bar struct{} func (b Bar) ImplementsFooer() {} func (b Bar) Foo() {}
大多数代码都没有使用这些约束,因为它们限制了接口思想的实用性。但有时,它们必须解决类似界面之间的歧义。
所以ProtoMessage()
方法基本上有两个目的:
proto.Message
接口但不是“真正的”protobuf消息值:
ProtoMessage充当标记,以确保没有人意外地实现proto.Message接口。Message
的事实。这可能没有真正的价值,因为代码是生成的,你不应该费心,但代码分析器和Go IDE可以很好地利用它;它也出现在生成的文档中。