type Man struct {
Id int
Name string
}
s1 := make([]Man, 0)
s1 = append(s1, Man{1, "a"})
s1 = append(s1, Man{2, "b"})
s1 = append(s1, Man{3, "c"})
func(v interface{}) {
getValue := reflect.ValueOf(v) // Value of v
if getValue.Kind() != reflect.Slice {
panic("need slice kind")
}
l := getValue.Len()
for i := 0; i < l; i++ {
value := getValue.Index(i) // Value of item
typel := value.Type() // Type of item
if typel.Kind() != reflect.Struct {
panic("need struct kind")
}
fmt.Printf("type-kind: %s, type-name: %s, value: %v\n", typel.Kind(), typel.Name(), value.Interface())
num := value.NumField()
for j := 0; j < num; j++ {
fmt.Printf("name: %s, type: %s, value: %v\n", typel.Field(j).Name, value.Field(j).Type(), value.Field(j).Interface())
}
fmt.Println()
}
}(s1)
打印信息
type-kind: struct, type-name: Man, value: {1 a}
name: Id, type: int, value: 1
name: Name, type: string, value: a
type-kind: struct, type-name: Man, value: {2 b}
name: Id, type: int, value: 2
name: Name, type: string, value: b
type-kind: struct, type-name: Man, value: {3 c}
name: Id, type: int, value: 3
name: Name, type: string, value: c
根据示例:
- 通过 reflect.ValueOf(v) 得到 v 的 Value 对象,它的 Len() 方法可以得到切片的长度;
- 通过 Value 对象的 Index(i) 方法得到第 i 的元素 Value 对象,然后通过 Value 对象得到 Type 对象;
Index 方法可以适用于 Array, Slice, or String
Len 方法可以适用于 Array, Chan, Map, Slice, or String
// Len returns v's length.
// It panics if v's Kind is not Array, Chan, Map, Slice, or String.
func (v Value) Len() int {
k := v.kind()
switch k {
case Array:
tt := (*arrayType)(unsafe.Pointer(v.typ))
return int(tt.len)
case Chan:
return chanlen(v.pointer())
case Map:
return maplen(v.pointer())
case Slice:
// Slice is bigger than a word; assume flagIndir.
return (*sliceHeader)(v.ptr).Len
case String:
// String is bigger than a word; assume flagIndir.
return (*stringHeader)(v.ptr).Len
}
panic(&ValueError{"reflect.Value.Len", v.kind()})
}
// Index returns v's i'th element.
// It panics if v's Kind is not Array, Slice, or String or i is out of range.
func (v Value) Index(i int) Value {
switch v.kind() {
case Array:
tt := (*arrayType)(unsafe.Pointer(v.typ))
if uint(i) >= uint(tt.len) {
panic("reflect: array index out of range")
}
typ := tt.elem
offset := uintptr(i) * typ.size
// Either flagIndir is set and v.ptr points at array,
// or flagIndir is not set and v.ptr is the actual array data.
// In the former case, we want v.ptr + offset.
// In the latter case, we must be doing Index(0), so offset = 0,
// so v.ptr + offset is still the correct address.
val := add(v.ptr, offset, "same as &v[i], i < tt.len")
fl := v.flag&(flagIndir|flagAddr) | v.flag.ro() | flag(typ.Kind()) // bits same as overall array
return Value{typ, val, fl}
case Slice:
// Element flag same as Elem of Ptr.
// Addressable, indirect, possibly read-only.
s := (*sliceHeader)(v.ptr)
if uint(i) >= uint(s.Len) {
panic("reflect: slice index out of range")
}
tt := (*sliceType)(unsafe.Pointer(v.typ))
typ := tt.elem
val := arrayAt(s.Data, i, typ.size, "i < s.Len")
fl := flagAddr | flagIndir | v.flag.ro() | flag(typ.Kind())
return Value{typ, val, fl}
case String:
s := (*stringHeader)(v.ptr)
if uint(i) >= uint(s.Len) {
panic("reflect: string index out of range")
}
p := arrayAt(s.Data, i, 1, "i < s.Len")
fl := v.flag.ro() | flag(Uint8) | flagIndir
return Value{uint8Type, p, fl}
}
panic(&ValueError{"reflect.Value.Index", v.kind()})
}