本文主要是介绍经过99次失败后, 我总结了几点 Golang 反射的经验(附源码),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

// kind_type_test.go

// 打印 kind 和 type 的值
func kind_type_value(v interface{}) {
	rv := reflect.ValueOf(v)
	fmt.Println(rv.Kind(), rv.Type())
}

// kind 和 type 相同字面值
func Test_Kind_Type_Same(t *testing.T) {
	name := "tangxin"
	age := 18

	kind_type_value(name) // string string
	kind_type_value(age)  // int int

	kind_type_value(&name) // ptr *string
	kind_type_value(&age)  // ptr *int
}
// 根据内置类型 string 的自定义类型
type MyString string

// kind 和 type 不同
func Test_KindType_Different(t *testing.T) {
	p := Person{
		Name: "tagnxin",
		Age:  18,
	}
	kind_type_value(p)  // struct main.Person
	kind_type_value(&p) // ptr *main.Person

	s1 := MyString("tangxin")
	kind_type_value(s1)  // string main.MyString
	kind_type_value(&s1) // ptr *main.MyString
}
// 第一定律: 对象类型转指针类型
func Test_Rule1(t *testing.T) {
	p := &Person{
		Name: "zhangsan",
		Age:  18,
		Addr: struct {
			City string
		}{
			City: "chengdu",
		},
	}
	rule1(p)  // ptr *main.Person
	rule1(&p) // ptr **main.Person
}

func rule1(v interface{}) {
	rv := reflect.ValueOf(v)
	fmt.Println(rv.Kind(), rv.Type())
}
func rule2(rv reflect.Value) {
	// check
	if !rv.CanInterface() {
		fmt.Println("rv is not settable: ", rv.Type())
		return
	}

	// convert
	rv = DerefValue(rv)
	irv := rv.Interface()
	fmt.Println(irv)

	// type assert
	v, ok := irv.(Person)
	fmt.Println(v, ok) // {zhangsan 18 {chengdu}} true

}
func rule3(rv reflect.Value) {
	if !rv.CanSet() {
		fmt.Println("rv is not settable", rv.Type())
		return
	}

	switch rv.Kind() {
	case reflect.String:
		rv.SetString("tangxin")
	case reflect.Int:
		rv.SetInt(333)
	default:
		fmt.Println("not support kind: ", rv.Kind())
	}
}
const (
	Invalid Kind = iota
	Bool
	Int
  // ...
  String
  // ...
	Interface
	Map
	Ptr  // 这里是重点, 指针可以只想任何容器类型,包括指针本身。
)
func Indirect(v Value) Value {
	if v.Kind() != Ptr {
		return v
	}
	return v.Elem()
}
// rule1_test.go
// 指向指针的指针对象
func Test_Rule1(t *testing.T) {
	p := &Person{
		Name: "zhangsan",
		Age:  18,
		Addr: struct {
			City string
		}{
			City: "chengdu",
		},
	}

	rv := reflect.ValueOf(&p)
	fmt.Println(rv.Kind(), rv.Type()) // ptr **main.Person
}

// value.go
// DerefValue 返回最底层的反射容器对象
func DerefValue(rv reflect.Value) reflect.Value {
	for rv.Kind() == reflect.Ptr {
		rv = rv.Elem()
	}

	return rv
}
type student struct {
	Name string
	Age  int
}

func (stu *student) SetDefaults() {
	stu.Name = "tangxin"
	if stu.Age == 0 {
		stu.Age = 100
	}
}

// 没有传参数的方法
func (stu *student) Greeting() {
	fmt.Printf("hello %s, %d years old\n", stu.Name, stu.Age)
}

// 具有传参数的方法
func (stu *student) Aloha(name string) {
	fmt.Println("aloha,", name)
}

func Test_MethodCall(t *testing.T) {
	stu := student{
		Name: "wangwu",
	}

	// 注意
	// 方法对象的方法接收者, 可以是 **指针对象** 也可以是 **结构体对象**
	// 如果是指针对象的方法, **结构体对象** 是不能调用起方法的
	rv := reflect.ValueOf(stu)
	prv := reflect.ValueOf(&stu)

	stu.Greeting()
	methodCall(prv, "SetDefaults")
	methodCall(rv, "Greeting") // 结构体接收者, 找不到方法
	methodCall(prv, "Aloha", reflect.ValueOf("boss"))
}

// 对象方法调用
// rv 目标对象, method 方法名称, in 参数
func methodCall(rv reflect.Value, method string, in ...reflect.Value) {

	// 通过方法名称获取 反射的方法对象
	mv := rv.MethodByName(method)
	// check mv 是否存在
	if !mv.IsValid() {
		fmt.Printf("mv is zero value, method %s not found\n", method)
		return
	}

	// 调用
	// nil 这里代表参数
	mv.Call(in)
}



这篇关于经过99次失败后, 我总结了几点 Golang 反射的经验(附源码)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!