Files
yanzuoguang 4092ddd6d8 feat(reflect): 添加结构体反射检查和字段操作功能
- 新增 inspectStructs 函数用于检查多个结构体类型
- 实现 inspectStructType递归检查结构体字段信息
- 添加 describeField 函数描述指定字段及其父级信息
- 新增 inspectTags 函数检查结构体标签信息
- 实现 getFieldValues 和 setFieldValues 操作结构体字段值
- 在 main.go 中调用新增的 main25、main26、main27 示例函数
- 扩展 types.go 中的结构体定义以支持新功能演示
2025-11-01 21:08:14 +08:00

455 lines
12 KiB
Go

package main
import (
"reflect"
"strings"
)
func createPointerType(t reflect.Type) reflect.Type {
return reflect.PointerTo(t)
}
func followPointerType(t reflect.Type) reflect.Type {
if t.Kind() == reflect.Ptr {
return t.Elem()
}
return t
}
func main15() {
Printfln("\nmain15:")
name := "Alice"
t := reflect.TypeOf(name)
Printfln("Original Type: %v", t)
pt := createPointerType(t)
Printfln("Pointer Type: %v", pt)
Printfln("Pointer Type: %v", followPointerType(pt))
}
var stringPtrType = reflect.TypeOf((*string)(nil))
func transformString(val interface{}) {
elemValue := reflect.ValueOf(val)
if elemValue.Type() == stringPtrType {
if elemValue.CanAddr() {
Printfln("Can address pointer addr: %v", elemValue.Addr())
}
elem := elemValue.Elem()
if elem.CanAddr() {
Printfln("Can address Follow pointer addr: %v", elem.Addr())
}
upperStr := strings.ToUpper(elem.String())
if elem.CanSet() {
elem.SetString(upperStr)
}
}
}
func main16() {
Printfln("\nmain16:")
name := "Alice"
transformString(&name)
Printfln("Follow pointer value: %v addr: %p", name, &name)
}
func checkElemType(val interface{}, arrOrSlice interface{}) bool {
elemType := reflect.TypeOf(val)
arrOrSliceType := reflect.TypeOf(arrOrSlice)
return (arrOrSliceType.Kind() == reflect.Array ||
arrOrSliceType.Kind() == reflect.Slice) &&
arrOrSliceType.Elem() == elemType
}
func main17() {
Printfln("\nmain17:")
name := "Alice"
city := "London"
hobby := "Running"
slice := []string{name, city, hobby}
array := [3]string{name, city, hobby}
Printfln("Slice (string): %v", checkElemType("testString", slice))
Printfln("Array (string): %v", checkElemType("testString", array))
Printfln("Slice (int): %v", checkElemType(10, slice))
}
func setValue(arrayOrSlice interface{}, index int, replacement interface{}) {
arrayOrSliceVal := reflect.ValueOf(arrayOrSlice)
replacementVal := reflect.ValueOf(replacement)
if arrayOrSliceVal.Kind() == reflect.Slice {
elemVal := arrayOrSliceVal.Index(index)
if elemVal.CanSet() {
elemVal.Set(replacementVal)
}
} else if arrayOrSliceVal.Kind() == reflect.Ptr &&
arrayOrSliceVal.Elem().Kind() == reflect.Array &&
arrayOrSliceVal.Elem().CanSet() {
elemVal := arrayOrSliceVal.Elem().Index(index)
if elemVal.CanSet() {
elemVal.Set(replacementVal)
}
}
}
func main18() {
Printfln("\nmain18:")
name := "Alice"
city := "London"
hobby := "Running"
slice := []string{name, city, hobby}
array := [3]string{name, city, hobby}
Printfln("Original slice:%v", slice)
newCity := "Paris"
setValue(slice, 1, newCity)
Printfln("Modified slice:%v", slice)
Printfln("Original array:%v", array)
newCity = "Rome"
setValue(&slice, 1, newCity)
Printfln("Modified array:%v", array)
}
func enumerateStrings(arrayOrSlice interface{}) {
arrayOrSliceVal := reflect.ValueOf(arrayOrSlice)
if (arrayOrSliceVal.Kind() == reflect.Slice ||
arrayOrSliceVal.Kind() == reflect.Array) &&
arrayOrSliceVal.Type().Elem().Kind() == reflect.String {
for i := 0; i < arrayOrSliceVal.Len(); i++ {
Printfln("Element Index: %v, Value: %v", i, arrayOrSliceVal.Index(i).String())
}
}
}
func main19() {
Printfln("\nmain19:")
name := "Alice"
city := "London"
hobby := "Running"
slice := []string{name, city, hobby}
array := [3]string{name, city, hobby}
enumerateStrings(slice)
enumerateStrings(array)
}
func findAndSplit(slice interface{}, target interface{}) interface{} {
sliceVal := reflect.ValueOf(slice)
targetType := reflect.TypeOf(target)
if sliceVal.Kind() == reflect.Slice && sliceVal.Type().Elem() == targetType {
for i := 0; i < sliceVal.Len(); i++ {
// Interface 取值
if sliceVal.Index(i).Interface() == target {
return sliceVal.Slice(0, i+1)
}
}
}
return slice
}
func main20() {
Printfln("\nmain20:")
name := "Alice"
city := "London"
hobby := "Running"
slice := []string{name, city, hobby}
Printfln("Strings slice:%v", findAndSplit(slice, "London"))
numbers := []int{1, 3, 4, 5, 7}
Printfln("Numbers slice:%v", findAndSplit(numbers, 4))
}
func pickValues(slice interface{}, indices ...int) interface{} {
sliceVal := reflect.ValueOf(slice)
if sliceVal.Kind() == reflect.Slice {
newSlice := reflect.MakeSlice(sliceVal.Type(), 0, len(indices))
for _, index := range indices {
if index < sliceVal.Len() {
newSlice = reflect.Append(newSlice, sliceVal.Index(index))
}
}
return newSlice
}
return nil
}
func main21() {
Printfln("\nmain21:")
name := "Alice"
city := "London"
hobby := "Running"
slice := []string{name, city, hobby, "Bob", "Paris", "Soccer"}
picked := pickValues(slice, 0, 3, 5)
Printfln("Picked values :%v", picked)
}
func describeMap(m interface{}) {
mapType := reflect.TypeOf(m)
if mapType.Kind() == reflect.Map {
Printfln("Key type : %v , Val Type: %v", mapType.Key(), mapType.Elem())
} else {
Printfln("Not a map")
}
}
func main22() {
Printfln("\nmain22:")
priceMap := map[string]float64{
"Kayak": 279,
"Lifejacket": 48.95,
"Soccer Ball": 19.50,
}
describeMap(priceMap)
printMapContents(priceMap)
printMapContents2(priceMap)
}
func printMapContents(m interface{}) {
mapValue := reflect.ValueOf(m)
if mapValue.Kind() == reflect.Map {
for _, key := range mapValue.MapKeys() {
Printfln("printMapContents Key: %v, Value: %v", key, mapValue.MapIndex(key))
}
} else {
Printfln("Not a map")
}
}
func printMapContents2(m interface{}) {
mapValue := reflect.ValueOf(m)
if mapValue.Kind() == reflect.Map {
iter := mapValue.MapRange()
for iter.Next() {
Printfln("printMapContents2 Key: %v, Value: %v", iter.Key(), iter.Value())
}
} else {
Printfln("Not a map")
}
}
func setMap(m interface{}, key interface{}, val interface{}) {
mapValue := reflect.ValueOf(m)
keyValue := reflect.ValueOf(key)
valValue := reflect.ValueOf(val)
if mapValue.Kind() == reflect.Map &&
mapValue.Type().Key() == keyValue.Type() &&
mapValue.Type().Elem() == valValue.Type() {
mapValue.SetMapIndex(keyValue, valValue)
} else {
Printfln("setMap Not a map or miss matched types")
}
}
func removeFromMap(m interface{}, key interface{}) {
mapValue := reflect.ValueOf(m)
keyValue := reflect.ValueOf(key)
if mapValue.Kind() == reflect.Map &&
mapValue.Type().Key() == keyValue.Type() {
mapValue.SetMapIndex(keyValue, reflect.Value{})
} else {
Printfln("removeFromMap Not a map or miss matched types")
}
}
func main23() {
Printfln("\nmain22:")
priceMap := map[string]float64{
"Kayak": 279,
"Lifejacket": 48.95,
"Soccer Ball": 19.50,
}
setMap(priceMap, "Kayak", 100.00)
setMap(priceMap, "Soccer Ball", 10.00)
removeFromMap(priceMap, "Lifejacket")
for key, val := range priceMap {
Printfln("Key: %v, Value: %v", key, val)
}
}
func createMap(slice interface{}, op func(interface{}) interface{}) interface{} {
sliceVal := reflect.ValueOf(slice)
if sliceVal.Kind() == reflect.Slice {
mapType := reflect.MapOf(sliceVal.Type().Elem(), sliceVal.Type().Elem())
mapVal := reflect.MakeMap(mapType)
for i := 0; i < sliceVal.Len(); i++ {
elemVal := sliceVal.Index(i)
mapVal.SetMapIndex(elemVal, reflect.ValueOf(op(elemVal.Interface())))
}
return mapVal.Interface()
}
return nil
}
func main24() {
Printfln("\nmain24:")
names := []string{"Alice", "Bob", "Charlie", "David"}
reverse := func(val interface{}) interface{} {
if str, ok := val.(string); ok {
return strings.ToUpper(str)
}
return val
}
namesMap := createMap(names, reverse)
for key, val := range namesMap.(map[string]string) {
Printfln("Key: %v, Value: %v", key, val)
}
}
func inspectStructs(structs ...interface{}) {
for _, s := range structs {
structType := reflect.TypeOf(s)
if structType.Kind() == reflect.Struct {
inspectStructType("main", []int{}, structType, structType)
}
}
}
func inspectStructType(tag string, baseIndex []int, structType reflect.Type, baseType reflect.Type) {
Printfln("--- %v Struct Type: %v", tag, structType)
for i := 0; i < structType.NumField(); i++ {
fieldIndex := append(baseIndex, i)
field := structType.Field(i)
Printfln("%v - Field Base Index : %v , Field Index %v: Name:%v, Type:%v, Tag:%v , PkgPath:%v",
tag, fieldIndex, field.Index, field.Name, field.Type, field.Tag, field.PkgPath)
if field.Type.Kind() == reflect.Struct {
inspectStructType("field", fieldIndex, field.Type, baseType)
fieldWithFieldIndex := baseType.FieldByIndex(fieldIndex)
inspectStructType("fieldWithFieldIndex", fieldIndex, fieldWithFieldIndex.Type, baseType)
}
}
Printfln("--- End %v Struct Type: %v", tag, structType)
}
func describeField(s interface{}, fieldName string) {
Printfln("\ndescribeField:")
structType := reflect.TypeOf(s)
field, found := structType.FieldByName(fieldName)
if found {
Printfln("Top-Level Type: %v, Name: %v, Type: %v, Index: %v, Tag:%v , PkgPath:%v",
structType, field.Name, field.Type, field.Index, field.Tag, field.PkgPath)
index := field.Index
for len(index) > 1 {
index = index[0 : len(index)-1]
parentField := structType.FieldByIndex(index)
Printfln("Parent Name: %v, Type: %v, Index: %v, Tag:%v , PkgPath:%v",
parentField.Name, parentField.Type, parentField.Index, parentField.Tag, parentField.PkgPath)
}
} else {
Printfln("Field %v not found", fieldName)
}
}
func main25() {
Printfln("\nmain25:")
inspectStructs(Purchase{})
describeField(Purchase{}, "Price")
}
func inspectTags(s interface{}, tagName string) {
structType := reflect.TypeOf(s)
for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i)
tag := field.Tag
valGet := tag.Get(tagName)
valLookup, ok := tag.Lookup(tagName)
Printfln("Field Name: %v, Type: %v, Tag: %v, TagName: %v, Get: %v, Lookup: %v, LookupOk: %v",
field.Name, field.Type, tag, tagName, valGet, valLookup, ok)
}
}
func main26() {
Printfln("\nmain26:")
inspectTags(Person{}, "alias")
stringType := reflect.TypeOf("")
structType := reflect.StructOf([]reflect.StructField{
{Name: "Name", Type: stringType, Tag: `alias:"id"`},
{Name: "City", Type: stringType, Tag: `alias:""`},
{Name: "Country", Type: stringType},
})
inspectTags(reflect.New(structType), "alias")
inspectTags(reflect.New(structType).Elem().Interface(), "alias")
}
func getFieldValues(s interface{}) {
structValue := reflect.ValueOf(s)
if structValue.Kind() != reflect.Struct {
Printfln("Not a struct")
return
}
for i := 0; i < structValue.NumField(); i++ {
fieldType := structValue.Type().Field(i)
fieldVal := structValue.Field(i)
Printfln("Name: %v, Type: %v, Value: %v", fieldType.Name, fieldType.Type, fieldVal)
}
}
func setFieldValues(s interface{}, newVals map[string]interface{}) {
structValue := reflect.ValueOf(s)
if structValue.Kind() != reflect.Ptr || structValue.Elem().Kind() != reflect.Struct {
Printfln("Not a pointer to a struct")
return
}
structValue = structValue.Elem()
for name, newValue := range newVals {
fieldVal := structValue.FieldByName(name)
if fieldVal.CanSet() {
fieldVal.Set(reflect.ValueOf(newValue))
} else if fieldVal.CanAddr() {
ptr := fieldVal.Addr()
if ptr.CanSet() {
ptr.Set(reflect.ValueOf(newValue))
} else {
Printfln("Can't set field via pointer: %v", name)
}
} else {
Printfln("Can't set field: %v", name)
}
}
}
func main27() {
Printfln("\nmain27:")
product := Product{Name: "Kayak", Category: "Watersports", Price: 279}
customer := Customer{Name: "Acme", City: "Chicago"}
Purchase := Purchase{Customer: customer, Product: product, Total: 279, taxRate: 10}
getFieldValues(Purchase)
Printfln("sets:")
setFieldValues(&Purchase, map[string]interface{}{
"City": "London",
"Category": "Boats",
"Total": 100.50,
})
getFieldValues(Purchase)
}