golang之reflect

reflect,反射。

利用reflect,可以得到一个struct的相关信息。

package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Id int
	Name string
	Age int
}

func (u User) Hello(name string) {
	fmt.Printf("hello %s, my name is %s\n", name, u.Name)
}

type Manager struct {
	User
	title string
}

func main() {
	// modify variable through reflect
	//x := 123
	//v := reflect.ValueOf(&x)
	//v.Elem().SetInt(234)
	//fmt.Println(x)

	u := User{1, "xiaoming", 12}
	u.Hello("atom")

	// call method through reflect
	v := reflect.ValueOf(u)
	mv := v.MethodByName("Hello")
	args := []reflect.Value{reflect.ValueOf("jack")}
	mv.Call(args)

	Info(u)
	Set(&u)
	Info(u)

	m := Manager{User{1, "xiaoming", 12}, "rd"}
	// get nested struct field
	t := reflect.TypeOf(m)
	fmt.Printf("%#v\n", t.Field(0))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0,0}))
}

func Info(i interface{}) {
	t := reflect.TypeOf(i)

	if t.Kind() != reflect.Struct {
		fmt.Println("Type Error")
		return
	}
	fmt.Println("Type:", t.Name())

	v := reflect.ValueOf(i)

	// get fields
	fmt.Println("Fields:")
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		val := v.Field(i).Interface()
		fmt.Printf("%6s: %v = %v\n", f.Name, f.Type, val)
	}
	// get methods
	fmt.Println("Methods:")
	for i := 0; i < t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Printf("%6s: %v\n", m.Name, m.Type)
	}
}

func Set(i interface{}) {
	v := reflect.ValueOf(i)
	if v.Kind() != reflect.Ptr || !v.Elem().CanSet() {
		fmt.Println("Error")
		return
	} else {
		v = v.Elem()
	}

	f := v.FieldByName("Name")
	if !f.IsValid() {
		fmt.Println("Bad Field")
	}
	if f.Kind() == reflect.String {
		f.SetString("byebye")
	}
}

输出如下:

hello atom, my name is xiaoming
hello jack, my name is xiaoming


Type: User
Fields:
Id: int = 1
Name: string = xiaoming
Age: int = 12
Methods:
Hello: func(main.User, string)


Type: User
Fields:
Id: int = 1
Name: string = byebye
Age: int = 12
Methods:
Hello: func(main.User, string)


reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x10d9e00), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}
reflect.StructField{Name:"Id", PkgPath:"", Type:(*reflect.rtype)(0x10c4e60), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false}

 

需要注意的一个地方是:

结构体的field首字母需要大写,否则会报错"panic: reflect.Value.Interface: cannot return value obtained from unexported field or method"

 

参考资料

Go编程基础

posted @ 2018-03-14 19:24  Sawyer Ford  阅读(387)  评论(0编辑  收藏  举报