
protobuf的`repeated`字段在构建时并不提供内置的排序功能。要确保这些字段中的元素有序,开发者必须在将数据添加到protobuf构建器之前,手动使用标准集合api对数据列表进行排序。protobuf的java和kotlin api均不支持在元素添加到构建器后进行排序操作,因此预排序是实现有序`repeated`字段的唯一有效方法。
在Protobuf定义中,repeated关键字用于声明一个可以包含零个或多个相同类型元素的字段,类似于编程语言中的列表或数组。例如:
message Dependency {
int32 id = 1;
string name = 2;
}
message Info {
repeated Dependency f1 = 1;
repeated Dependency f2 = 2;
}这里,f1和f2都是Dependency对象的列表。然而,Protobuf协议本身并没有为repeated字段提供内置的排序机制。这意味着当你向Protobuf构建器添加元素时,它们会按照添加的顺序存储。一旦消息被构建,Protobuf的Java或Kotlin API都不提供直接的方法来对已添加到构建器中的repeated字段进行排序。因此,如果应用程序需要repeated字段中的元素始终保持特定顺序,就必须在数据被添加到Protobuf消息之前完成排序。
确保Protobuf repeated 字段元素有序的唯一有效方法是“预排序”,即在将元素添加到Protobuf构建器之前,先对它们进行排序。这个过程通常涉及以下几个步骤:
这种方法确保了在Protobuf消息被序列化之前,其内部的列表就已经是有序的。
以下是一个Java语言的示例,演示如何对Info消息中的f1字段进行排序:
首先,假设我们有以下Protobuf定义(example.proto):
syntax = "proto3";
option java_package = "com.example.protobuf";
option java_outer_classname = "ExampleProto";
message Dependency {
int32 id = 1;
string name = 2;
}
message Info {
repeated Dependency f1 = 1;
repeated Dependency f2 = 2;
}然后,在Java代码中实现排序:
package com.example.protobuf;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ProtobufSortingExample {
public static void main(String[] args) {
// 1. 创建一些 Dependency 对象
Dependency dep1 = Dependency.newBuilder().setId(3).setName("ModuleC").build();
Dependency dep2 = Dependency.newBuilder().setId(1).setName("ModuleA").build();
Dependency dep3 = Dependency.newBuilder().setId(2).setName("ModuleB").build();
Dependency dep4 = Dependency.newBuilder().setId(4).setName("ModuleD").build();
// 2. 将它们添加到可变列表中
List<Dependency> dependencies = new ArrayList<>();
dependencies.add(dep1);
dependencies.add(dep2);
dependencies.add(dep3);
dependencies.add(dep4);
System.out.println("原始顺序:");
dependencies.forEach(dep -> System.out.println(" ID: " + dep.getId() + ", Name: " + dep.getName()));
// 3. 对列表进行排序(例如,按ID升序)
// 使用 Collections.sort 和自定义 Comparator
Collections.sort(dependencies, new Comparator<Dependency>() {
@Override
public int compare(Dependency d1, Dependency d2) {
return Integer.compare(d1.getId(), d2.getId());
}
});
// 或者使用 Java 8 Lambda 表达式:
// dependencies.sort(Comparator.comparingInt(Dependency::getId));
System.out.println("\n排序后(按ID):");
dependencies.forEach(dep -> System.out.println(" ID: " + dep.getId() + ", Name: " + dep.getName()));
// 4. 将排序后的列表添加到 Protobuf 构建器中
Info info = Info.newBuilder()
.addAllF1(dependencies) // 添加排序后的列表
// 可以为 f2 添加其他未排序或按其他方式排序的列表
// .addAllF2(...)
.build();
// 验证 Protobuf 消息中的顺序
System.out.println("\nProtobuf Info 消息中的 f1 字段顺序:");
info.getF1List().forEach(dep -> System.out.println(" ID: " + dep.getId() + ", Name: " + dep.getName()));
// 尝试添加未排序的列表到 f2 字段进行对比
List<Dependency> unsortedDependencies = new ArrayList<>();
unsortedDependencies.add(Dependency.newBuilder().setId(5).setName("ModuleE").build());
unsortedDependencies.add(Dependency.newBuilder().setId(6).setName("ModuleF").build());
unsortedDependencies.add(Dependency.newBuilder().setId(4).setName("ModuleD").build()); // 故意重复一个ID
Info infoWithUnsortedF2 = Info.newBuilder()
.addAllF1(dependencies) // f1 仍然是排序后的
.addAllF2(unsortedDependencies) // f2 是未排序的
.build();
System.out.println("\nProtobuf Info 消息中的 f2 字段顺序(未排序):");
infoWithUnsortedF2.getF2List().forEach(dep -> System.out.println(" ID: " + dep.getId() + ", Name: " + dep.getName()));
}
}运行上述代码,你将看到f1字段中的Dependency对象是按照id升序排列的,而f2字段则保持了原始的添加顺序。
尽管Protobuf本身不提供repeated字段的内置排序功能,但通过在将数据添加到Protobuf构建器之前进行“预排序”,开发者可以有效地控制这些字段中元素的顺序。这种方法利用了宿主语言(如Java或Kotlin)的标准集合排序能力,是实现有序Protobuf repeated 字段的唯一且推荐的实践。理解并应用这一策略,对于构建数据结构清晰、符合业务逻辑要求的Protobuf消息至关重要。
以上就是Protobuf重复字段排序指南的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号