常见类型
到目前为止,如果你查看了配套的代码,你会看到我们定义了许多 “无聊” 的类型,这些类型只是围绕一个字段的包装器。需要注意的是,我们手动编写了这些类型,仅仅是为了给出一个如何检查特定数据序列化的示例。大多数情况下,你将能够使用已经定义的类型,它们做的事情是一样的。
常见类型(Well-known Types)
Protobuf
本身提供了一些已经定义好的类型,我们称之为 “知名类型”(well-known types)。虽然它们中的大多数在 Protobuf
库本身之外或在高级用例中很少使用,但其中一些是很重要的,我们将在本书中使用其中的一些。
我们可以很容易理解的是 “包装器”(wrappers)。我们之前手动编写了一些包装器。它们通常以它们所包装的类型的名称开头,最后以 Value
结尾。以下是包装器类型的列表:
-
BoolValue
-
BytesValue
-
DoubleValue
-
EnumValue
-
FloatValue
-
Int32Value
-
Int64Value
-
StringValue
-
UInt32Value
-
UInt64Value
这些类型可能在调试用例中很有用,比如我们之前看到的用例,或者仅仅用于序列化简单的数据,如数字、字符串等。
然后,Protobuf
还定义了表示时间的类型,比如 Duration
和 Timestamp
。这两种类型的定义完全相同([Duration | Timestamp]
并不是有效的 Protobuf
语法,它表示我们可以选择其中任何一个术语):
message [Duration | Timestamp] {
// 表示自 Unix 纪元(1970-01-01T00:00:00Z)以来的 UTC 时间秒数。
// 必须在 0001-01-01T00:00:00Z 到 9999-12-31T23:59:59Z 之间。
int64 seconds = 1;
// 秒的非负小数部分,精确到纳秒。负秒值与小数部分必须具有非负的纳秒值,
// 并且时间应该向前推进。必须在 0 到 999,999,999 之间。
int32 nanos = 2;
}
然而,正如它们的名字所示,它们表示不同的概念。Duration
类型表示开始时间和结束时间之间的差异,而 Timestamp
类型表示一个简单的时间点。
最后,一个重要的知名类型是 FieldMask
。这个类型表示一组字段,指示在序列化另一个类型时应包含哪些字段。为了更好理解这一点,我们来看一个例子。假设我们有一个 API 端点返回一个账户,其中包含 id、用户名和电子邮件。如果你只想获取账户的电子邮件地址,以便准备发送促销邮件给一部分人,你可以使用 FieldMask
类型告诉 Protobuf
只序列化电子邮件字段。这样,我们就可以减少序列化和反序列化的额外开销,因为现在我们只处理一个字段,而不是三个。
Google 公共类型
除了知名类型之外,还有一些由 Google 定义的类型。这些类型在 googleapis/api-common-protos
GitHub 仓库的 google/type
目录下定义,并且在 Golang 代码中很容易使用。我鼓励你查看所有这些类型,但我想提到其中一些有趣的类型:
-
LatLng:一个纬度/经度对,将值存储为双精度浮点数(double)。
-
Money:一个金额及其货币,货币类型按照 ISO 4217 标准定义。
-
Date:由
int32
类型表示的年月日。
再次提醒,建议你访问该仓库查看所有其他类型。这些类型经过了大量的实际应用和测试,通常比我们自己编写的简单类型更优化。然而,也要注意,这些类型可能并不适合你的所有用例。没有一种类型能适用于所有场景。