获取一个FieldDescriptor而不硬编码字段名(proto消息)

huangapple go评论79阅读模式
英文:

Get a FieldDescriptor without hard-coding the field name (proto message)

问题

给定以下的 proto message:

message MyMsg {
  string my_field = 1;
  string your_field=2;
}

...可以使用 protoreflect 包来获取每个字段的描述符:

protoMessage := myMsg.ProtoReflect()
messageDescriptor := protoMessage.Descriptor() // protobuf 类型信息
fieldDescriptors := messageDescriptor.Fields() // 字段声明列表

获取特定字段的 field descriptor 很简单:

fieldDescriptor := fieldDescriptors.ByTextName("my_field") // 描述一个字段

是否可以在不硬编码字段名 "my_field" 的情况下实现这一点?我猜如果能使用生成的代码来引用我感兴趣的字段会很好。类似于(不是有效的代码):

fieldDescriptor := fieldDescriptors.ByTextName(pb.MyMsg.MyField) // 描述一个字段

这样,如果字段名发生变化,它将在编译时被捕获,甚至可以通过 IDE 的静态分析来捕获。

FieldDescriptors 类型有三个通过名称获取字段描述符的方法:

  • ByName(s Name)
  • ByJSONName(s string)
  • ByTextName(s string)

ByJSONNameByTextName 都需要硬编码的字段名(作为字符串),而 ByName 接受一个 Name,它被类型化为字符串。总之,我在 protoreflect 包中没有找到指向解决方案的任何内容。

背景

Field masks 是支持部分资源更新的推荐方法。在字段掩码中提供的掩码上进行迭代非常简单:

protoMessage := myMsg.ProtoReflect()
messageDescriptor := protoMessage.Descriptor() // protobuf 类型信息
fieldDescriptors := messageDescriptor.Fields() // 字段声明列表

// 在字段掩码中迭代字段路径
for _, p := range mask.GetPaths() {

	// 找到字段路径的字段描述符
	fieldDescriptor := fieldDescriptors.ByTextName(p)

	if fieldDescriptor == nil {
		// 找不到字段路径的字段描述符
		return
	}

	// 太好了,字段路径指向一个字段,让我们使用它

	switch p {
	case "my_field":
		// 客户端想要更新 MyMsg.my_field

	case "your_field":
		// 客户端想要更新 MyMsg.your_field
	}
}

问题是,为了实际更新 MyMsg 中的正确字段,有必要在 switch 语句中硬编码字段名。

英文:

Given the following proto message

message MyMsg {
  string my_field = 1;
  string your_field=2;
}

...the protoreflect package can be used to get a descriptor for each field

protoMessage := myMsg.ProtoReflect()
messageDescriptor := protoMessage.Descriptor() // protobuf type information
fieldDescriptors := messageDescriptor.Fields() // list of field declarations

Getting a field descriptor for a specific field is trivial

fieldDescriptor := fieldDescriptors.ByTextName("my_field") // describes a field

Can this be achieved without hard-coding the field name "my_field"? I guess it would be nice to use the generated code to refer to the field I'm interested in. Something like (not working code)

fieldDescriptor := fieldDescriptors.ByTextName(pb.MyMsg.MyField) // describes a field

This way, if the field name changes, it will be caught at compile time, or even from static analysis by an IDE.

The FieldDescriptors type has three methods for getting a field descriptor by name:

  • ByName(s Name)
  • ByJSONName(s string)
  • ByTextName(s string)

ByJSONName and ByTextName both require hard-coded field names (as strings), and by ByName accepts a Name which is type'd to a string. The upshot is, I don't see anything in the protoreflect package that points to a solution.

Context

Field masks are the recommended way to support partial resource updates. It's trivial to iterate over the masks provided in a field mask

protoMessage := myMsg.ProtoReflect()
messageDescriptor := protoMessage.Descriptor() // protobuf type information
fieldDescriptors := messageDescriptor.Fields() // list of field declarations

// iterate over the field paths in the field mask
for _, p := range mask.GetPaths() {

	// find the field descriptor for the field path
	fieldDescriptor := fieldDescriptors.ByTextName(p)

	if fieldDescriptor == nil {
		// field descriptor cannot be found for the field path
		return
	}

	// great, the field path points to a field, let's use it

	switch p {
	case "my_field":
		// the client wants to update MyMsg.my_field

	case "your_field":
		// the client wants to update  MyMsg.your_field
	}
}

The problem is, in order to actually update the correct field in MyMsg, it's necessary to hard-code the field name in the switch statement.

答案1

得分: 1

接口也有ByNumber方法。

我假设(我没有使用过这个方法),你可以从你的示例中给出1

当然还有Get方法,这样你就可以枚举所有的FieldDescriptors。

我认为想要反射生成的(结构体)类型并在它们之间进行枚举是合理的,但感觉像是无穷递归。

如果你能提出你无法在没有所需方法的情况下解决的问题,可能会有其他答案帮到你。

英文:

The interface has ByNumber too

I assume (I've not used the method) that you could give this 1 from your example.

And Get, of course so that you can enumerate all of the FieldDescriptors.

I think it's not unreasonable to want to reflect (!) the generated (struct) types and enumerate across them but it feels like turtles-all-the-way-down.

It may help solicit other answers if you could present the problem that you're unable to solve without the desired method?

huangapple
  • 本文由 发表于 2021年9月8日 02:07:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/69092776.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定