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

根据示例:

  1. 通过 reflect.ValueOf(v) 得到 v 的 Value 对象,它的 Len() 方法可以得到切片的长度;
  2. 通过 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()})
}