oleiade/reflections

GitHub: oleiade/reflections

一个 Go 语言反射辅助库,在标准库 reflect 之上提供更直观的高层抽象,简化运行时结构体字段与标签的访问操作。

Stars: 535 | Forks: 51

# 反射 [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/) [![Build Status](https://static.pigsec.cn/wp-content/uploads/repos/cas/2a/2a44ebb2294c01676e19eed14adc6cea930435b1ac09f01b83d80f1ec8c274bf.svg)](https://github.com/oleiade/reflections/actions/workflows/go.yml) [![Go Documentation](https://pkg.go.dev/badge/github.com/oleiade/reflections)](https://pkg.go.dev/github.com/oleiade/reflections) [![Go Report Card](https://goreportcard.com/badge/github.com/oleiade/reflections)](https://goreportcard.com/report/github.com/oleiade/reflections) ![Go Version](https://img.shields.io/github/go-mod/go-version/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分析, 日志审计