Editions 的特性设置

Protobuf 版本的功能以及它们如何影响 protobuf 的行为。

本主题概述了已发布的版本中包含的功能。后续版本的功能将被添加到本主题中。我们会在新闻版块中公布新版本。

在新的 schema 定义内容中配置功能设置之前,请确保你理解为什么使用它们。避免在功能上盲目跟风

Prototiller

Prototiller 是一个命令行工具,用于在语法版本和版本之间更新 proto schema 配置文件。它尚未发布,但在本主题中有多处引用。

功能

以下各节包含了所有可通过版本中的功能进行配置的行为。保留 proto2 或 proto3 行为展示了如何覆盖默认行为,使你的 proto 定义文件像 proto2 或 proto3 文件一样工作。有关版本和功能如何协同设置行为的更多信息,请参阅 Protobuf 版本概述

功能设置在不同级别生效

文件级别:这些设置适用于所有未设置覆盖项的元素(消息、字段、枚举等)。

非嵌套:消息、枚举和服务可以覆盖在文件级别进行的设置。这些设置适用于它们内部所有未被覆盖的内容(消息字段、枚举值),但不适用于其他并列的消息和枚举。

嵌套:oneof、消息和枚举可以覆盖它们所嵌套的消息中的设置。

最低级别:字段、扩展、枚举值、扩展范围和方法是你可以覆盖设置的最低级别。

以下各节都有一条注释,说明了该功能可以应用的作用域。以下示例展示了一个应用于每个作用域的模拟功能

edition = "2024";

// File-level scope definition
option features.bar = BAZ;

enum Foo {
  // Enum (non-nested scope) definition
  option features.bar = QUX;

  A = 1;
  B = 2;
}

message Corge {
  // Message (non-nested scope) definition
  option features.bar = QUUX;

  message Garply {
    // Message (nested scope) definition
    option features.bar = WALDO;
    string id = 1;
  }

  // Field (lowest-level scope) definition
  Foo A = 1 [features.bar = GRAULT];
}

在此示例中,最低级别作用域功能定义中的设置“GRAULT"覆盖了非嵌套作用域的“QUUX”设置。而在 Garply 消息中,“WALDO”覆盖了“QUUX”。

features.default_symbol_visibility

此功能可设置消息和枚举的默认可见性,使它们在被其他 proto 文件导入时可用或不可用。使用此功能将减少无效符号,以创建更小的二进制文件。

除了为整个文件设置默认值外,你还可以使用 localexport 关键字来设置每个字段的行为。更多相关信息请阅读 export / local 关键字

可用值

  • EXPORT_ALL:这是 2024 版之前的默认值。所有消息和枚举默认都被导出。
  • EXPORT_TOP_LEVEL:所有顶层符号默认为导出;嵌套符号默认为本地。
  • LOCAL_ALL:所有符号默认为本地。
  • STRICT:所有符号默认为本地。嵌套类型不能被导出,除了 message { enum {} reserved 0 to max; } 的特殊情况。这将在未来的版本中成为默认值。

适用于以下作用域:枚举、消息

添加于:2024 版

各语法/版本的默认行为

语法/版本默认值
2024EXPORT_TOP_LEVEL
2023EXPORT_ALL
proto3EXPORT_ALL
proto2EXPORT_ALL

注意:不同 schema 元素上的功能设置具有不同的作用域

以下示例展示了如何将该功能应用于你的 proto schema 定义文件中的元素

// foo.proto
edition = "2024";

// Symbol visibility defaults to EXPORT_TOP_LEVEL. Setting
// default_symbol_visibility overrides these defaults
option features.default_symbol_visibility = LOCAL_ALL;

// Top-level symbols are exported by default in Edition 2024; applying the local
// keyword overrides this
export message LocalMessage {
  int32 baz = 1;
  // Nested symbols are local by default in Edition 2024; applying the export
  // keyword overrides this
  enum ExportedNestedEnum {
    UNKNOWN_EXPORTED_NESTED_ENUM_VALUE = 0;
  }
}

// bar.proto
edition = "2024";

import "foo.proto";

message ImportedMessage {
  // The following is valid because the imported message explicitly overrides
  // the visibility setting in foo.proto
  LocalMessage bar = 1;

  // The following is not valid because default_symbol_visibility is set to
  // `LOCAL_ALL`
  // LocalMessage.ExportedNestedEnum qux = 2;
}

features.enforce_naming_style

此功能在 2024 版中引入,它启用了风格指南中定义的严格命名风格强制执行,以确保 proto 默认是可往返转换的,并提供一个功能值来选择退出

可用值

  • STYLE2024:强制严格遵守风格指南的命名规范。
  • STYLE_LEGACY:应用 2024 版之前的风格指南强制执行级别。

适用于以下作用域:文件

添加于:2024 版

各语法/版本的默认行为

语法/版本默认值
2024STYLE2024
2023STYLE_LEGACY
proto3STYLE_LEGACY
proto2STYLE_LEGACY

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 2023 版的文件

2023 版默认为 STYLE_LEGACY,所以一个不符合规范的字段名是可以的

edition = "2023";

message Foo {
  // A non-conforming field name is not a problem
  int64 bar_1 = 1;
}

2024 版默认为 STYLE2024,所以需要一个覆盖来保留不符合规范的字段名

edition = "2024";

// To keep the non-conformant field name, override the STYLE2024 setting
option features.enforce_naming_style = "STYLE_LEGACY";

message Foo {
  int64 bar_1 = 1;
}

features.enum_type

此功能设置了如何处理不在定义集合内的枚举值的行为。有关开放和封闭枚举的更多信息,请参阅枚举行为

此功能不影响 proto3 文件,因此本节没有 proto3 文件的前后对比。

可用值

  • CLOSED: 封闭枚举将超出范围的枚举值存储在未知字段集中。
  • OPEN: 开放枚举将超出范围的值直接解析到它们的字段中。

适用于以下作用域:文件、枚举

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024OPEN
2023OPEN
proto3OPEN
proto2CLOSED

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

enum Foo {
  A = 2;
  B = 4;
  C = 6;
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

enum Foo {
  // Setting the enum_type feature overrides the default OPEN enum
  option features.enum_type = CLOSED;
  A = 2;
  B = 4;
  C = 6;
}

features.field_presence

此功能设置了跟踪字段存在性的行为,即 protobuf 字段是否具有值的概念。

可用值

  • LEGACY_REQUIRED:该字段在解析和序列化时是必需的。任何显式设置的值都会被序列化到线路上传输(即使它与默认值相同)。
  • EXPLICIT:该字段具有显式存在性跟踪。任何显式设置的值都会被序列化到线路上传输(即使它与默认值相同)。对于单一原始类型字段,会为设置为 EXPLICIT 的字段生成 has_* 函数。
  • IMPLICIT:该字段没有存在性跟踪。默认值不会被序列化到线路上传输(即使它是显式设置的)。不会为设置为 IMPLICIT 的字段生成 has_* 函数。

适用于以下作用域:文件、字段

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024EXPLICIT
2023EXPLICIT
proto3IMPLICIT*
proto2EXPLICIT

* proto3 是 IMPLICIT,除非字段带有 optional 标签,在这种情况下,它的行为类似于 EXPLICIT。有关更多信息,请参阅Proto3 API 中的存在性

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

message Foo {
  required int32 x = 1;
  optional int32 y = 2;
  repeated int32 z = 3;
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

message Foo {
  // Setting the field_presence feature retains the proto2 required behavior
  int32 x = 1 [features.field_presence = LEGACY_REQUIRED];
  int32 y = 2;
  repeated int32 z = 3;
}

下面展示了一个 proto3 文件

syntax = "proto3";

message Bar {
  int32 x = 1;
  optional int32 y = 2;
  repeated int32 z = 3;
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";
// Setting the file-level field_presence feature matches the proto3 implicit default
option features.field_presence = IMPLICIT;

message Bar {
  int32 x = 1;
  // Setting the field_presence here retains the explicit state that the proto3
  // field has because of the optional syntax
  int32 y = 2 [features.field_presence = EXPLICIT];
  repeated int32 z = 3;
}

请注意,requiredoptional 标签在版本中不再存在,因为相应的行为通过 field_presence 功能显式设置。

features.json_format

此功能设置了 JSON 解析和序列化的行为。

此功能不影响 proto3 文件,因此本节没有 proto3 文件的前后对比。版本的行为与 proto3 中的行为匹配。

可用值

  • ALLOW:运行时必须允许 JSON 解析和序列化。在 proto 级别进行检查,以确保存在明确定义的到 JSON 的映射。
  • LEGACY_BEST_EFFORT:运行时尽力解析和序列化 JSON。允许某些 proto,这可能导致运行时出现未指定的行为(例如多对一或一对多映射)。

适用于以下作用域:文件、消息、枚举

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024ALLOW
2023ALLOW
proto3ALLOW
proto2LEGACY_BEST_EFFORT

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

message Foo {
  // Warning only
  string bar = 1;
  string bar_ = 2;
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";
option features.json_format = LEGACY_BEST_EFFORT;

message Foo {
  string bar = 1;
  string bar_ = 2;
}

features.message_encoding

此功能设置了序列化时字段的编码行为。

此功能不影响 proto3 文件,因此本节没有 proto3 文件的前后对比。

根据语言的不同,那些“类 group”的字段在生成的代码和文本格式中可能会有一些意想不到的大小写,以提供与 proto2 的向后兼容性。如果满足以下所有条件,消息字段就是“类 group”的

  • 指定了 DELIMITED 消息编码
  • 消息类型与字段在同一作用域内定义
  • 字段名与类型名的小写形式完全相同

可用值

  • LENGTH_PREFIXED:字段使用消息结构中描述的 LEN 线路类型进行编码。
  • DELIMITED:消息类型字段被编码为

适用于以下作用域:文件、字段

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024LENGTH_PREFIXED
2023LENGTH_PREFIXED
proto3LENGTH_PREFIXED
proto2LENGTH_PREFIXED

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

message Foo {
  group Bar = 1 {
    optional int32 x = 1;
    repeated int32 y = 2;
  }
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

message Foo {
  message Bar {
    int32 x = 1;
    repeated int32 y = 2;
  }
  Bar bar = 1 [features.message_encoding = DELIMITED];
}

features.repeated_field_encoding

此功能是 proto2/proto3 中用于 repeated 字段的 packed 选项在版本中迁移到的目标。

可用值

  • PACKED:原始类型的 Repeated 字段被编码为单个 LEN 记录,其中包含每个元素的串联。
  • EXPANDEDRepeated 字段的每个值都使用字段编号进行编码。

适用于以下作用域:文件、字段

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024PACKED
2023PACKED
proto3PACKED
proto2EXPANDED

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

message Foo {
  repeated int32 bar = 6 [packed=true];
  repeated int32 baz = 7;
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";
option features.repeated_field_encoding = EXPANDED;

message Foo {
  repeated int32 bar = 6 [features.repeated_field_encoding=PACKED];
  repeated int32 baz = 7;
}

下面展示了一个 proto3 文件

syntax = "proto3";

message Foo {
  repeated int32 bar = 6;
  repeated int32 baz = 7 [packed=false];
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

message Foo {
  repeated int32 bar = 6;
  repeated int32 baz = 7 [features.repeated_field_encoding=EXPANDED];
}

features.utf8_validation

此功能设置了如何验证字符串。它适用于所有语言,除非有特定语言的 utf8_validation 功能覆盖它。有关 Java 语言特定功能,请参阅 features.(pb.java).utf8_validation

此功能不影响 proto3 文件,因此本节没有 proto3 文件的前后对比。

可用值

  • VERIFY:运行时应验证 UTF-8。这是 proto3 的默认行为。
  • NONE:该字段在线路上的行为类似于未经验证的 bytes 字段。解析器可能以不可预测的方式处理此类字段,例如替换无效字符。这是 proto2 的默认行为。

适用于以下作用域:文件、字段

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024VERIFY
2023VERIFY
proto3VERIFY
proto2NONE

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

message MyMessage {
  string foo = 1;
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

message MyMessage {
  string foo = 1 [features.utf8_validation = NONE];
}

特定语言的功能

一些功能适用于特定语言,而不适用于其他语言中的相同 proto。使用这些功能需要你从该语言的运行时导入相应的 *_features.proto 文件。以下各节中的示例展示了这些导入。

features.(pb.go).api_level

语言:Go

api_level 功能使你能够选择 Go protobuf 插件应为哪个 API 版本生成代码。Opaque API 是 Go 编程语言 Protocol Buffers 实现的最新版本。之前的版本现在称为 Open Struct API。有关介绍,请参阅 Go Protobuf:发布 Opaque API 博文。

可用值

  • API_OPEN:Open Struct API 生成可直接访问的结构体类型。
  • API_HYBRID:Hybrid 是 Open 和 Opaque 之间的一个步骤:Hybrid API 也包含访问器方法(以便你更新代码),但仍然像以前一样导出结构体字段。性能上没有差异;此 API 级别仅有助于迁移。
  • API_OPAQUE:使用 Opaque API,结构体字段被隐藏,不再能直接访问。取而代之的是,新的访问器方法允许获取、设置或清除字段。

适用于以下作用域:消息、文件

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2023API_OPEN
2024API_OPAQUE

注意:不同 schema 元素上的功能设置具有不同的作用域

你可以从 2023 版开始设置 api_level 功能

edition = "2023";

import "google/protobuf/go_features.proto";

// Remove this line after migrating the code to the Opaque API.
option features.(pb.go).api_level = API_HYBRID;

另请参阅:Opaque API:迁移

features.(pb.cpp).enum_name_uses_string_view

语言:C++

在 2024 版之前,所有生成的枚举类型都提供以下函数来从枚举值中获取标签,这在运行时构造 std::string 实例时会有一些开销

const std::string& Foo_Name(int);

2024 版中的默认功能值将此签名更改为返回 absl::string_view,以实现更好的存储解耦和潜在的内存/CPU 节省。如果你尚未准备好迁移,可以覆盖此设置以将其恢复为之前的行为。有关此主题的更多信息,请参阅迁移指南中的string_view 返回类型

可用值

  • true:枚举使用 string_view 作为其值。
  • false:枚举使用 std::string 作为其值。

适用于以下作用域:枚举、文件

添加于:2024 版

各语法/版本的默认行为

语法/版本默认值
2024true
2023false
proto3false
proto2false

注意:不同 schema 元素上的功能设置具有不同的作用域

features.(pb.java).large_enum

语言:Java

这个特定于语言的功能使你能够采用新功能,在 Java 中处理大型枚举而不会导致编译器错误。请注意,此功能复制了类似枚举的行为,但有一些显著差异。例如,不支持 switch 语句。

可用值

  • true:Java 枚举将使用新功能。
  • false:Java 枚举将继续使用 Java 枚举。

适用于以下作用域:枚举

添加于:2024 版

各语法/版本的默认行为

语法/版本默认值
2024false
2023false
proto3false
proto2false

注意:不同 schema 元素上的功能设置具有不同的作用域

features.(pb.cpp/pb.java).legacy_closed_enum

语言:C++、Java

此功能决定了一个具有开放枚举类型的字段是否应表现得像一个封闭枚举。这使得版本能够在 Java 和 C++ 中重现来自 proto2 和 proto3 的不合规行为

此功能不影响 proto3 文件,因此本节没有 proto3 文件的前后对比。

可用值

  • true:无论 enum_type 如何设置,都将枚举视为封闭的。
  • false:遵守 enum_type 中的设置。

适用于以下作用域:文件、字段

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024false
2023false
proto3false
proto2true

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

import "myproject/proto3file.proto";

message Msg {
  myproject.proto3file.Proto3Enum name = 1;
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

import "myproject/proto3file.proto";

import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";

message Msg {
  myproject.proto3file.Proto3Enum name = 1 [
    features.(pb.cpp).legacy_closed_enum = true,
    features.(pb.java).legacy_closed_enum = true
  ];
}

features.(pb.java).nest_in_file_class

语言:Java

此功能控制 Java 生成器是否将在生成的 Java 文件类中嵌套生成的类。将此选项设置为 NO 等同于在 proto2/proto3/2023 版中设置 java_multiple_files = true

默认的外部类名也更新为默认情况下始终是驼峰式 .proto 文件名加上 Proto 后缀(例如,foo/bar_baz.proto 变为 BarBazProto)。你仍然可以使用 java_outer_classname 文件选项覆盖此设置,并替换 2024 版之前的默认值 BarBazBarBazOuterClass,具体取决于是否存在冲突。

可用值

  • NO:不要在文件类中嵌套生成的类。
  • YES:在文件类中嵌套生成的类。
  • Legacy:设置 java_multiple_files 选项时使用的内部值。

适用于以下作用域:消息、枚举、服务

添加于:2024 版

各语法/版本的默认行为

语法/版本默认值
2024NO
2023LEGACY
proto3LEGACY
proto2LEGACY

注意:不同 schema 元素上的功能设置具有不同的作用域

features.(pb.cpp).string_type

语言:C++

此功能决定了生成的代码应如何处理字符串字段。这取代了 proto2 和 proto3 中的 ctype 选项,并提供了一个新的 string_type 功能。在 2023 版中,你可以在字段上指定 ctypestring_type,但不能同时指定两者。在 2024 版中,ctype 选项被移除。

可用值

  • VIEW:为字段生成 string_view 访问器。
  • CORD:为字段生成 Cord 访问器。不支持扩展字段。
  • STRING:为字段生成 string 访问器。

适用于以下作用域:文件、字段

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024VIEW
2023STRING
proto3STRING
proto2STRING

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

message Foo {
  optional string bar = 6;
  optional string baz = 7 [ctype = CORD];
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

import "google/protobuf/cpp_features.proto";

message Foo {
  string bar = 6 [features.(pb.cpp).string_type = STRING];
  string baz = 7 [features.(pb.cpp).string_type = CORD];
}

下面展示了一个 proto3 文件

syntax = "proto3"

message Foo {
  string bar = 6;
  string baz = 7 [ctype = CORD];
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

import "google/protobuf/cpp_features.proto";

message Foo {
  string bar = 6 [features.(pb.cpp).string_type = STRING];
  string baz = 7 [features.(pb.cpp).string_type = CORD];
}

features.(pb.java).utf8_validation

语言:Java

这个特定于语言的功能使你能够仅在 Java 中在字段级别覆盖文件级别的设置。

此功能不影响 proto3 文件,因此本节没有 proto3 文件的前后对比。

可用值

  • DEFAULT:行为与 features.utf8_validation 设置的行为相匹配。
  • VERIFY:覆盖文件级别的 features.utf8_validation 设置,强制仅为 Java 设置为 VERIFY

适用于以下作用域:字段、文件

添加于:2023 版

各语法/版本的默认行为

语法/版本默认值
2024DEFAULT
2023DEFAULT
proto3DEFAULT
proto2DEFAULT

注意:不同 schema 元素上的功能设置具有不同的作用域

以下代码示例展示了一个 proto2 文件

syntax = "proto2";

option java_string_check_utf8=true;

message MyMessage {
  string foo = 1;
  string bar = 2;
}

运行 Prototiller 后,等效的代码可能如下所示

edition = "2024";

import "google/protobuf/java_features.proto";

option features.utf8_validation = NONE;
option features.(pb.java).utf8_validation = VERIFY;
message MyMessage {
  string foo = 1;
  string bar = 2;
}

features.(pb.go).strip_enum_prefix

语言:Go

枚举值不受其包含的枚举名称的作用域限制,因此建议为每个值添加枚举名称作为前缀

edition = "2024";

enum Strip {
  STRIP_ZERO = 0;
  STRIP_ONE = 1;
}

然而,现在生成的 Go 代码将包含两个前缀!

type Strip int32

const (
    Strip_STRIP_ZERO Strip = 0
    Strip_STRIP_ONE  Strip = 1
)

特定于语言的 strip_enum_prefix 功能决定了 Go 代码生成器是否剥离重复的前缀。

可用值

  • STRIP_ENUM_PREFIX_KEEP:保持名称原样,即使是重复的。
  • STRIP_ENUM_PREFIX_GENERATE_BOTH:生成完整名称和剥离后的名称两者(以帮助迁移你的 Go 代码)。
  • STRIP_ENUM_PREFIX_STRIP:从枚举值名称中剥离枚举名称前缀。

适用于以下作用域:枚举、文件

添加于:2024 版

各语法/版本的默认行为

语法/版本默认值
2024STRIP_ENUM_PREFIX_KEEP

注意:不同 schema 元素上的功能设置具有不同的作用域

你可以在 2024 版(或更新版本)的 .proto 文件中设置 strip_enum_prefix 功能

edition = "2024";

import "google/protobuf/go_features.proto";

option features.(pb.go).strip_enum_prefix = STRIP_ENUM_PREFIX_STRIP;

enum Strip {
  STRIP_ZERO = 0;
  STRIP_ONE = 1;
}

现在生成的 Go 代码将剥离 STRIP 前缀

type Strip int32

const (
    Strip_ZERO Strip = 0
    Strip_ONE  Strip = 1
)

在 2023 版中保留 proto2 或 proto3 行为

你可能希望迁移到版本格式,但暂时不想处理生成的代码行为的更新。本节展示了 Prototiller 工具对你的 .proto 文件所做的更改,以使基于 2023 版的 proto 表现得像 proto2 或 proto3 文件。

在文件级别进行这些更改后,你将获得 proto2 或 proto3 的默认值。你可以在更低的级别(消息级别、字段级别)进行覆盖,以考虑其他行为差异(例如 required、proto3 optional),或者如果你希望你的定义只是*大部分*像 proto2 或 proto3。

我们建议使用 Prototiller,除非你有特殊原因不使用。要手动应用所有这些更改而不是使用 Prototiller,请将以下各节的内容添加到你的 .proto 文件的顶部。

Proto2 行为

下面显示了使用 2023 版复制 proto2 行为的设置。

edition = "2023";

import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";

option features.field_presence = EXPLICIT;
option features.enum_type = CLOSED;
option features.repeated_field_encoding = EXPANDED;
option features.json_format = LEGACY_BEST_EFFORT;
option features.utf8_validation = NONE;
option features.(pb.cpp).legacy_closed_enum = true;
option features.(pb.java).legacy_closed_enum = true;

Proto3 行为

下面显示了使用 2023 版复制 proto3 行为的设置。

edition = "2023";

import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";

option features.field_presence = IMPLICIT;
option features.enum_type = OPEN;
// `packed=false` needs to be transformed to field-level repeated_field_encoding
// features in Editions syntax
option features.json_format = ALLOW;
option features.utf8_validation = VERIFY;
option features.(pb.cpp).legacy_closed_enum = false;
option features.(pb.java).legacy_closed_enum = false;

从 2023 版到 2024 版

下面显示了使用 2024 版复制 2023 版行为的设置。

// foo/bar_baz.proto
edition = "2024";

import option "third_party/protobuf/cpp_features.proto";
import option "third_party/java/protobuf/java_features.proto";
import option "third_party/golang/protobuf/v2/src/google/protobuf/go_features.proto";

// If previously relying on edition 2023 default java_outer_classname.
option java_outer_classname = "BarBaz" // or BarBazOuterClass

option features.(pb.cpp).string_type = STRING;
option features.enforce_naming_style = STYLE_LEGACY;
option features.default_symbol_visibility = EXPORT_ALL;
option features.(pb.cpp).enum_name_uses_string_view = false;
option features.(pb.go).api_level = API_OPEN;

message MyMessage {
  option features.(pb.java).nest_in_file_class = YES;
}

注意事项与例外

本节展示了如果你选择不使用 Prototiller,需要手动进行的更改。

设置上一节中显示的文件级默认值可以在大多数情况下设置默认行为,但有一些例外。

2023 版及更高版本

  • optional:移除所有 optional 标签的实例,如果文件默认值为 IMPLICIT,则将 features.field_presence 更改为 EXPLICIT
  • required:移除所有 required 标签的实例,并在字段级别添加 features.field_presence=LEGACY_REQUIRED 选项。
  • groups:将 groups 解包到一个单独的消息中,并在字段级别添加 features.message_encoding = DELIMITED 选项。有关更多信息,请参阅 features.message_encoding
  • java_string_check_utf8:移除此文件选项,并用 features.(pb.java).utf8_validation 替换。你需要导入 Java 功能,如 特定语言的功能 中所述。
  • packed:对于转换为版本格式的 proto2 文件,移除 packed 字段选项,并在不希望使用在 Proto2 行为 中设置的 EXPANDED 行为时,在字段级别添加 [features.repeated_field_encoding=PACKED]。对于转换为版本格式的 proto3 文件,当不希望使用默认的 proto3 行为时,在字段级别添加 [features.repeated_field_encoding=EXPANDED]

2024 版及更高版本