oleiade/reflections
GitHub: oleiade/reflections
一个 Go 语言反射辅助库,在标准库 reflect 之上提供更直观的高层抽象,简化运行时结构体字段与标签的访问操作。
Stars: 535 | Forks: 51
# 反射
[](https://choosealicense.com/licenses/mit/)
[](https://github.com/oleiade/reflections/actions/workflows/go.yml)
[](https://pkg.go.dev/github.com/oleiade/reflections)
[](https://goreportcard.com/report/github.com/oleiade/reflections)

`reflections` 库在 go 语言标准 `reflect` 库的基础上提供了高级抽象。
在实践中,`reflect` 库的 API 有点底层且不够直观。使用它可能会变得相当复杂、令人生畏和害怕,尤其是在执行一些简单的操作时,比如访问结构体字段值、字段 tag 等。
`reflections` 包旨在让开发者在运行时检查结构体值时变得更加轻松。它的 API 从 Python 语言的 `getattr,` `setattr,` 和 `hasattr` 系列方法中汲取了灵感,并提供了对结构体字段和 tag 的简化访问。
- [Reflections](#reflections)
- [文档](#documentation)
- [用法](#usage)
- [`GetField`](#getfield)
- [`GetFieldKind`](#getfieldkind)
- [`GetFieldType`](#getfieldtype)
- [`GetFieldTag`](#getfieldtag)
- [`HasField`](#hasfield)
- [`Fields`](#fields)
- [`Items`](#items)
- [`Tags`](#tags)
- [`GetFieldNameByTagValue`](#getfieldnamebytagvalue)
- [重要说明](#important-notes)
- [贡献](#contribute)
## 文档
请访问[文档](https://pkg.go.dev/github.com/oleiade/reflections)以获取有关该库 API 的更多详细信息。
## 用法
### `GetField`
`GetField` 返回结构体字段的内容。例如,当您想遍历结构体特定的字段值时,它非常有用。您可以为 `GetField` 提供一个结构体或指向结构体的指针作为第一个参数。
```
s := MyStruct {
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
fieldsToExtract := []string{"FirstField", "ThirdField"}
for _, fieldName := range fieldsToExtract {
value, err := reflections.GetField(s, fieldName)
DoWhatEverWithThatValue(value)
}
```
### `GetFieldKind`
`GetFieldKind` 返回结构体字段的 [`reflect.Kind`](http://golang.org/src/pkg/reflect/type.go?s=6916:6930#L189)。您可以使用它在运行时对结构体字段进行类型断言。您可以为 `GetFieldKind` 提供一个结构体或指向结构体的指针作为第一个参数。
```
s := MyStruct{
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
var firstFieldKind reflect.String
var secondFieldKind reflect.Int
var err error
firstFieldKind, err = GetFieldKind(s, "FirstField")
if err != nil {
log.Fatal(err)
}
secondFieldKind, err = GetFieldKind(s, "SecondField")
if err != nil {
log.Fatal(err)
}
```
### `GetFieldType`
`GetFieldType` 返回结构体字段类型的字符串字面量。您可以使用它在运行时对结构体字段进行类型断言。您可以为 `GetFieldType` 提供一个结构体或指向结构体的指针作为第一个参数。
```
s := MyStruct{
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
var firstFieldKind string
var secondFieldKind string
var err error
firstFieldKind, err = GetFieldType(s, "FirstField")
if err != nil {
log.Fatal(err)
}
secondFieldKind, err = GetFieldType(s, "SecondField")
if err != nil {
log.Fatal(err)
}
```
### `GetFieldTag`
`GetFieldTag` 提取特定的结构体字段 tag。您可以为 `GetFieldTag` 提供一个结构体或指向结构体的指针作为第一个参数。
```
s := MyStruct{}
tag, err := reflections.GetFieldTag(s, "FirstField", "matched")
if err != nil {
log.Fatal(err)
}
fmt.Println(tag)
tag, err = reflections.GetFieldTag(s, "ThirdField", "unmatched")
if err != nil {
log.Fatal(err)
}
fmt.Println(tag)
```
### `HasField`
`HasField` 断言结构体中是否存在某个字段。您可以为 `HasField` 提供一个结构体或指向结构体的指针作为第一个参数。
```
s := MyStruct {
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
// has == true
has, _ := reflections.HasField(s, "FirstField")
// has == false
has, _ := reflections.HasField(s, "FourthField")
```
### `Fields`
`Fields` 返回结构体字段名称的列表,以便您稍后访问或更新它们。您可以为 `Fields` 提供一个结构体或指向结构体的指针作为第一个参数。
```
s := MyStruct {
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
var fields []string
// Fields will list every structure exportable fields.
// Here, it's content would be equal to:
// []string{"FirstField", "SecondField", "ThirdField"}
fields, _ = reflections.Fields(s)
```
### `Items`
`Items` 返回结构体的字段名到值的映射(map)。您可以为 `Items` 提供一个结构体或指向结构体的指针作为第一个参数。
```
s := MyStruct {
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
var structItems map[string]interface{}
// Items will return a field name to
// field value map
structItems, _ = reflections.Items(s)
```
### `Tags`
`Tags` 返回带有指定 key 的结构体字段 tag。您可以为 `Tags` 提供一个结构体或指向结构体的指针作为第一个参数。
```
s := MyStruct {
FirstField: "first value", `matched:"first tag"`
SecondField: 2, `matched:"second tag"`
ThirdField: "third value", `unmatched:"third tag"`
}
var structTags map[string]string
// Tags will return a field name to tag content
// map. N.B that only field with the tag name
// you've provided will be matched.
// Here structTags will contain:
// {
// "FirstField": "first tag",
// "SecondField": "second tag",
// }
structTags, _ = reflections.Tags(s, "matched")
```
### `SetField`
`SetField` 使用提供的值更新结构体的字段值。请注意,您无法设置未导出(un-exported)的字段,并且字段和值的类型必须匹配。
```
s := MyStruct {
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
//To be able to set the structure's values,
// it must be passed as a pointer.
_ := reflections.SetField(&s, "FirstField", "new value")
// If you try to set a field's value using the wrong type,
// an error will be returned
err := reflection.SetField(&s, "FirstField", 123) // err != nil
```
### `GetFieldNameByTagValue`
`GetFieldNameByTagValue` 会在提供的 `obj` 对象中查找带有匹配 `{tagKey}:"{tagValue}"` tag 的字段。
如果 `obj` 不是一个 `struct`,也不是一个 `pointer`,或者它没有带有 `tagKey` 和匹配 `tagValue` 的字段,此函数将返回一个错误。
```
s := MyStruct {
FirstField: "first value", `matched:"first tag"`
SecondField: 2, `matched:"second tag"`
ThirdField: "third value", `unmatched:"third tag"`
}
// Getting field name from external source as json would be a headache to convert it manually,
// so we get it directly from struct tag
// returns fieldName = "FirstField"
fieldName, _ = reflections.GetFieldNameByTagValue(s, "matched", "first tag");
// later we can do GetField(s, fieldName)
```
## 重要说明
- 使用 `reflections` 库无法访问或设置**未导出(Un-exported)字段**。Go 语言标准的 `reflect` 库有意禁止了对未导出字段值的访问或修改。
## 贡献
- 查看未解决的 issue,或者创建一个新的 issue,以便围绕某个功能想法或 bug 展开讨论。
- 在 GitHub 上 Fork [该仓库](http://github.com/oleiade/reflections),开始对 **master** 分支进行修改,或者从它创建一个新分支。
- 编写测试用例,证明 bug 已被修复或功能按预期工作。
- 发送一个 pull request 并提醒 maintainer 直到它被合并和发布。:) 确保将自己添加到 [`AUTHORS`](https://github.com/oleiade/reflections/blob/master/AUTHORS.md) 中。
标签:EVTX分析, 日志审计