- 新增 inspectStructs 函数用于检查多个结构体类型 - 实现 inspectStructType递归检查结构体字段信息 - 添加 describeField 函数描述指定字段及其父级信息 - 新增 inspectTags 函数检查结构体标签信息 - 实现 getFieldValues 和 setFieldValues 操作结构体字段值 - 在 main.go 中调用新增的 main25、main26、main27 示例函数 - 扩展 types.go 中的结构体定义以支持新功能演示
455 lines
12 KiB
Go
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)
|
|
}
|