zoukankan      html  css  js  c++  java
  • Go

    上一篇文章 说到了 Golang 中的反射的一些基本规则,重点就是文章中最后的三点,但是这篇文章并没有说如何在反射中调用函数和方法,这就是接下来要说的。

    反射中调用 函数

    众所周知,Golang 中的函数是可以像普通的 int、float 等类型变量那样作为值的,例如:

    package main
    
    import "fmt"
    
    func hello() {
    	fmt.Println("Hello world!")
    }
    
    func main() {
    	hl := hello
    	hl()
    }
    

    prints:

    hello world!
    

    既然函数可以像普通的类型变量一样可以的话,那么在反射机制中就和不同的变量是一样的,在反射中 函数 和 方法 的类型(Type)都是 reflect.Func,如果要调用函数的话,可以通过 Value 的 Call() 方法,例如:

    func main() {
    	hl := hello
    	fv := reflect.ValueOf(hl)
    	fmt.Println("fv is reflect.Func ?", fv.Kind() == reflect.Func)
    	fv.Call(nil)
    }

    prints:

    fv is reflect.Func? true
    hello world!
    

    Value 的 Call() 方法的参数是一个 Value 的 slice,对应的反射函数类型的参数,返回值也是一个 Value 的 slice,同样对应反射函数类型的返回值。通过这个例子,相信你一看就明白了:

    func prints(i int) string {
    	fmt.Println("i =", i)
    	return strconv.Itoa(i)
    }
    
    func main() {
    	fv := reflect.ValueOf(prints)
    	params := make([]reflect.Value, 1)                 // 参数
    	params[0] = reflect.ValueOf(20)                    // 参数设置为20
    	rs := fv.Call(params)                              // rs作为结果接受函数的返回值
    	fmt.Println("result:", rs[0].Interface().(string)) // 当然也可以直接是 rs[0].Interface()
    }

    prints:

    i = 20
    result: 20
    

    反射中调用 方法

    上面说了在反射中调用函数的例子,接下来我们要谈谈反射中方法的调用。函数和方法可以说其实本质上是相同的,只不过方法与一个“对象”进行了“绑定”,方法是“对象”的一种行为,这种行为是对于这个“对象”的一系列操作,例如修改“对象”的某个属性,如下所示:

    type MyType struct {
    	i    int
    	name string
    }
    
    func (mt *MyType) SetI(i int) {
    	mt.i = i
    }
    
    func (mt *MyType) SetName(name string) {
    	mt.name = name
    }
    
    func (mt *MyType) String() string {
    	return fmt.Sprintf("%p", mt) + "--name:" + mt.name + " i:" + strconv.Itoa(mt.i)
    }

    好了,现在类型和其对应的方法都已经准备好了,那接下来就是如何使用的问题了,我们有了上面调用函数的经验,只需要再了解一点知识就可以使用了,这一点知识就是 Method 和 MethodByName 的API,好了,现在都准备好了,我们就看看如何使用吧。

    func main() {
    	myType := &MyType{22, "golang"}
    	//fmt.Println(myType)     // 就是检查一下myType对象内容
    	//println("---------------")
    
    	mtV := reflect.ValueOf(&myType).Elem()
    	// 也可以使用
    	//mtV := reflect.ValueOf(myType)
    
    
    	fmt.Println("Before:", mtV.MethodByName("String").Call(nil)[0])
    
    	params := make([]reflect.Value, 1)
    	params[0] = reflect.ValueOf(18)
    	mtV.MethodByName("SetI").Call(params)
    
    	params[0] = reflect.ValueOf("reflection test")
    	mtV.MethodByName("SetName").Call(params)
    
    	fmt.Println("After:", mtV.MethodByName("String").Call(nil)[0])
    }

    prints:

    Before: address:0x18245050--name:golang i i:22
    After: address:0x18245050--name:reflection test i:18
    

    需要注意的是上面打印的地址是对象在内存的地址,如果你也运行了这段代码,结果这个地址应该是不同的。

    咦,就这样结束了吗?当然不是,细心的读者会发现上面提到的 Method 好像没用到啊,恩,是的,聪明的你一看 API 的介绍我相信你就知道如何将上面的代码转换成用 Method() 方法达到同样的效果:

    mtV := reflect.ValueOf(&myType).Elem()
    fmt.Println("Before:",mtV.Method(2).Call(nil)[0])
    params = make([]reflect.Value,1)
    params[0] = reflect.ValueOf(18)
    mtV.Method(0).Call(params)
    params[0] = reflect.ValueOf("reflection test")
    mtV.Method(1).Call(params)
    fmt.Println("After:",mtV.Method(2).Call(nil)[0])

    参考:

    http://golang.org/doc/articles/laws_of_reflection.html

    http://blog.csdn.net/wowzai/article/details/9327405

  • 相关阅读:
    bzoj2733: [HNOI2012]永无乡
    bzoj3141: [Hnoi2013]旅行
    bzoj3144: [Hnoi2013]切糕
    bzoj3140: [Hnoi2013]消毒
    bzoj3139: [Hnoi2013]比赛
    bzoj3142: [Hnoi2013]数列
    bzoj3572: [Hnoi2014]世界树
    bzoj2286: [Sdoi2011]消耗战
    bzoj3611: [Heoi2014]大工程
    The Unsolvable Problem
  • 原文地址:https://www.cnblogs.com/52php/p/6337420.html
Copyright © 2011-2022 走看看