当我从协议缓冲区文件生成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()方法的目的。该方法不带参数,也不返回参数,为什么会出现?
答案 0 :(得分:2)
引自官方文件: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
接口但不是a"真实" protobuf消息值:
ProtoMessage充当标记,以确保没有人意外地实现proto.Message接口。
Message
的事实。这可能没有真正的价值,因为代码是生成的,你不应该费心,但代码分析器和Go IDE可以很好地利用它;它也出现在生成的文档中。