概述

软件包fieldmaskpb包含google / protobuf / field_mask.proto的生成类型。

FieldMask消息表示一组符号字段路径。路径特定于某些目标消息类型,这些类型不存储在FieldMask消息本身中。

构建FieldMask

New函数用于构造FieldMask:

1
2
3
4
5
6
var messageType *descriptorpb.DescriptorProto
fm, err := fieldmaskpb.New(messageType, "field.name", "field.number")
if err != nil {
	... // handle error
}
... // make use of fm

根据google.protobuf.DescriptorProto消息,“field.name"和"field.number"路径是有效路径。使用与DescriptorProto可以访问的有效字段不相关的路径会导致错误。

构造FieldMask消息后,可以使用Append方法将其他路径插入路径集:

1
2
3
4
var messageType *descriptorpb.DescriptorProto
if err := fm.Append(messageType, "options"); err != nil {
	... // handle error
}

类型检查FieldMask

为了验证FieldMask是否代表可以从某些目标消息类型访问的一组字段,请使用IsValid方法:

1
2
3
4
var messageType *descriptorpb.DescriptorProto
if fm.IsValid(messageType) {
	... // make use of fm
}

IsValid必须传递目标消息类型作为输入,因为FieldMask消息本身并不存储路径集所针对的消息类型。

变量

1
var File_google_protobuf_field_mask_proto protoreflect.FileDescriptor

type FieldMask

1
2
3
4
5
6
type FieldMask struct {

	// The set of field mask paths.
	Paths []string `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"`
	// contains filtered or unexported fields
}

“FieldMask"代表一组符号字段路径,例如:

1
2
paths: "f.a"
paths: "f.b.d"

在这里,“f"代表某个根消息中的一个字段,“f"中发现的消息中的"a"和"b"字段,而"d"则是在"fb"消息中发现的字段。

字段掩码用于指定应由get操作返回或由update操作修改的字段子集。字段掩码还具有自定义JSON编码(请参见下文)。

在投影环境中使用时,API会过滤响应消息或子消息,以仅包含掩码中指定的那些字段。例如,如果将上一个示例中的掩码按如下方式应用于响应消息:

1
2
3
4
5
6
7
8
9
f {
  a22
  b {
    d1
    x2
  }
  y13
}
z8

结果将不包含字段x,y和z的特定值(它们的值将设置为默认值,并在原始文本输出中省略):

1
2
3
4
5
6
f {
  a22
  b {
    d1
  }
}

除非在路径字符串的最后位置,否则不允许重复字段。

如果get操作中不存在FieldMask对象,则该操作将应用于所有字段(就像已指定所有字段的FieldMask一样)。

请注意,字段掩码不一定适用于顶级响应消息。在进行REST获取操作的情况下,字段掩码直接应用于响应,但是在进行REST列表操作的情况下,该掩码改为应用于返回的资源列表中的每个消息。在REST自定义方法的情况下,可以使用其他定义。适用掩码的位置将在API中明确记录及其声明。无论如何,对返回的一个或多个资源的影响是API必需的行为。

更新操作中的字段掩码

更新操作中的字段掩码指定要更新目标资源的哪些字段。要求API仅更改掩码中指定的字段的值,而其他字段保持不变。如果传入资源来描述更新的值,则API将忽略掩码未涵盖的所有字段的值。

如果为更新操作指定了重复字段,则新值将附加到目标资源中现有的重复字段中。请注意,仅在`paths’字符串的最后位置允许重复字段。

如果在字段掩码的最后一个位置中指定了子消息以进行更新操作,则新值将合并到目标资源中的现有子消息中。

例如,给定目标消息:

1
2
3
4
5
6
7
f {
  b {
    d1
    x2
  }
  c[1]
}

以及一条更新消息:

1
2
3
4
5
6
f {
  b {
    d10
  }
  c[2]
}

然后,如果字段掩码是:

1
paths: ["f.b", "f.c"]

那么结果将是:

1
2
3
4
5
6
7
f {
  b {
    d: 10
    x: 2
  }
  c: [1, 2]
}

一个实现可以提供选项来覆盖重复字段和消息字段的默认行为。

为了将字段的值重置为默认值,该字段必须在掩码中,并在提供的资源中设置为默认值。因此,为了重置资源的所有字段,请提供资源的默认实例并在掩码中设置所有字段,或者不提供掩码,如下所述。

如果更新时不存在字段掩码,则该操作将应用于所有字段(就像已指定所有字段的字段掩码一样)。请注意,在存在模式演化的情况下,这可能意味着客户端不知道且因此未填写到请求中的字段将重置为默认值。如果这是不希望的行为,则特定服务可能要求客户端始终指定字段掩码,否则将产生错误。

与get操作一样,在请求消息中描述更新值的资源位置取决于操作种类。在任何情况下,API都必须遵守字段掩码的作用。

HTTP REST的注意事项

为了满足HTTP语义,必须将使用字段掩码的HTTP类型的更新操作设置为PATCH而不是PUT(PUT必须仅用于完全更新)。

字段掩码的JSON编码

在JSON中,字段掩码编码为单个字符串,其中路径之间用逗号分隔。每个路径中的字段名称都与小写骆驼命名约定相互转换。

例如,请考虑以下消息声明:

1
2
3
4
5
6
7
8
message Profile {
  User user = 1;
  Photo photo = 2;
}
message User {
  string display_name = 1;
  string address = 2;
}

在原型中,“配置文件"的域掩码可能看起来像这样:

1
2
3
4
mask {
  paths: "user.display_name"
  paths: "photo"
}

在JSON中,相同的掩码表示如下:

1
2
3
{
  mask: "user.displayName,photo"
}

字段掩码和Oneof字段

字段掩码将oneof中的字段视为常规字段。考虑以下消息:

1
2
3
4
5
6
message SampleMessage {
  oneof test_oneof {
    string name = 4;
    SubMessage sub_message = 9;
  }
}

字段掩码可以是:

1
2
3
mask {
  paths: "name"
}

或者:

1
2
3
mask {
  paths: "sub_message"
}

请注意,不能在路径中使用一个类型名称(在这种情况下为"test_oneof”)。

字段掩码验证

在请求中具有FieldMask类型字段的任何API方法的实现应验证所包含的字段路径,如果任何路径不可映射,则返回"INVALID_ARGUMENT"错误。

func Intersect

1
func Intersect(mx *FieldMask, my *FieldMask, ms ...*FieldMask) *FieldMask

Intersect返回输入字段掩码中所有路径的相交。

func New

1
func New(m proto.Message, paths ...string) (*FieldMask, error)

New根据路径列表构造一个字段掩码,并根据指定的消息类型验证每个掩码是否有效。

func Union

1
func Union(mx *FieldMask, my *FieldMask, ms ...*FieldMask) *FieldMask

Union返回输入字段掩码中所有路径的并集。

func (*FieldMask) Append

1
func (x *FieldMask) Append(m proto.Message, paths ...string) error

Append将一系列路径添加到掩码,并根据指定的消息类型验证每个路径是否有效。无效路径未附加,并中断了后续路径的插入。

func (*FieldMask) Descriptor

1
func (*FieldMask) Descriptor() ([]byte, []int)

不推荐使用:改用FieldMask.ProtoReflect.Descriptor。

func (*FieldMask) GetPaths

1
func (x *FieldMask) GetPaths() []string

func (*FieldMask) IsValid

1
func (x *FieldMask) IsValid(m proto.Message) bool

IsValid报告所有路径在语法上是否有效,并引用指定消息类型中的已知字段。对于零字段掩码,它报告为false。

func (*FieldMask) Normalize

1
func (x *FieldMask) Normalize()

规范化将掩码转换为规范形式,在该规范中,所有路径均已排序,冗余路径已删除。

func (*FieldMask) ProtoMessage

1
func (*FieldMask) ProtoMessage()

func (*FieldMask) ProtoReflect

1
func (x *FieldMask) ProtoReflect() protoreflect.Message

func (*FieldMask) Reset

1
func (x *FieldMask) Reset()

func (*FieldMask) String

func (x *FieldMask) String() string