when I generate go code from a protocol buffer file, I noticed that each of the generated structs implement the Message interface, https://github.com/golang/protobuf/blob/master/proto/lib.go#L277
For an example of the code that is generated, see https://github.com/google/go-genproto/blob/master/googleapis/rpc/status/status.pb.go#L97
Clearly, the other methods on Message interface, String() and Reset(), have an obvious purpose and the concrete implementation example makes that clear. However, I don't understand the purpose of the ProtoMessage() method. The method takes no parameters and returns no arguments, so why is it there?
Protocol buffers provide a language-neutral, platform-neutral, extensible mechanism for serializing structured data in a forward-compatible and backward-compatible way. It's like JSON, except it's smaller and faster, and it generates native language bindings.
Google made this protocol open source and now it provides support, out of the box, to the most common languages, like JavaScript, Java, C#, Ruby and others. In our tests, it was demonstrated that this protocol performed up to 6 times faster than JSON. "Protobuf performs up to 6 times faster than JSON."
Protobuf categorizes normally used data types into wire types which provides information to find the length of the value. For wire type 2, length is also encoded along with value. Zero values are not transmitted. 0, False, “”, does not take any bytes.
A protocol buffer message is a series of key-value pairs. The binary version of a message just uses the field's number as the key -- the name and declared type for each field can only be determined on the decoding end by referencing the message type's definition (that is, the . proto file).
Quoting from official doc: Protocol Buffers: Go Generated Code:
Given a simple message declaration:
message Foo {}
the protocol buffer compiler generates a struct called
Foo
. A*Foo
implements the Message interface. See the inline comments for more information.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() {}
Note that all of these members are always present; the
optimize_for
option does not affect the output of the Go code generator.
This is a (similar) technique described in Go official FAQ: How can I guarantee my type satisfies an interface?
If you wish the users of an interface to explicitly declare that they implement it, you can add a method with a descriptive name to the interface's method set. For example:
type Fooer interface { Foo() ImplementsFooer() }
A type must then implement the
ImplementsFooer
method to be aFooer
, clearly documenting the fact and announcing it in godoc's output.type Bar struct{} func (b Bar) ImplementsFooer() {} func (b Bar) Foo() {}
Most code doesn't make use of such constraints, since they limit the utility of the interface idea. Sometimes, though, they're necessary to resolve ambiguities among similar interfaces.
So the ProtoMessage()
method basically has 2 purposes:
proto.Message
interface but is not a "real" protobuf message value:
ProtoMessage acts as a tag to make sure no one accidentally implements the proto.Message interface.
Message
. This may not have a real value at first as the code is generated and you should not bother much with it, but code analyzers and Go IDE's may make good use of it; and it also appears in generated docs.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With