# 反射規則
在計算機科學領域,反射是指一類應用,它們能夠自描述和自控制。也就是說,這類應用通過采用某種機制來實現對自己行為的描述(self-representation)和監測(examination),并能根據自身行為的狀態和結果,調整或修改應用所描述行為的狀態和相關的語義。
> 每個語言的反射模型都不同(同時許多語言根本不支持反射)。
Go語言實現了反射,所謂反射就是動態運行時的狀態。
我們用到的包是reflect。
# 從接口值到反射對象的反射
> 反射僅是一種用來檢測存儲在接口變量內部(值value,實例類型concret type)pair對的一種機制。
在reflect反射包中有兩種類型讓我們可以訪問接口變量內容
- reflect.ValueOf()
~~~
// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i interface{}) Value {...}
~~~
- reflect.TypeOf()
~~~
// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i interface{}) Type {...}
~~~
一個簡單的案例:
~~~
package main
import (
"reflect"
"fmt"
)
type ControllerInterface interface {
Init(action string, method string)
}
type Controller struct {
Action string
Method string
Tag string `json:"tag"`
}
func (c *Controller) Init(action string, method string){
c.Action = action
c.Method = method
}
func main(){
//初始化
runController := &Controller{
Action:"Run1",
Method:"GET",
}
//Controller實現了ControllerInterface方法,因此它就實現了ControllerInterface接口
var i ControllerInterface
i = runController
// 得到實際的值,通過v我們獲取存儲在里面的值,還可以去改變值
v := reflect.ValueOf(i)
fmt.Println("value:",v)
// 得到類型的元數據,通過t我們能獲取類型定義里面的所有元素
t := reflect.TypeOf(i)
fmt.Println("type:",t)
// 轉化為reflect對象之后我們就可以進行一些操作了,也就是將reflect對象轉化成相應的值
......
}
~~~
> 打印結果:
value: &{Run1 GET}
type: *main.Controller
- v 是i接口為指向main包下struct Controller的指針(runController)目前的所存儲值
- t 是i接口為指向main包下struct Controller的指針類型。
### 轉換reflect對象之后操作
### 接口i所指向的對象的值操作
~~~
// Elem返回值v包含的接口
controllerValue := v.Elem()
fmt.Println("controllerType(reflect.Value):",controllerType)
//獲取存儲在第一個字段里面的值
fmt.Println("Action:", controllerValue.Field(0).String())
~~~
> controllerType(reflect.Value): {Run1 GET }
Action: Run1
### 接口i所指向的對象的類型操作
獲取定義在struct里面的標簽
~~~
// Elem返回類型的元素類型。
controllerType := t.Elem()
tag := controllerType.Field(2).Tag //Field(第幾個字段,index從0開始)
fmt.Println("Tag:", tag)
~~~
> Tag: json:”tag”
### 通過reflect.TypeOf(i)獲取對象方法的信息
~~~
method, _ := t.MethodByName("Init")
fmt.Println(method)
~~~
~~~
打印結果:
{Init func(*main.Controller, string, string) <func(*main.Controller, string, string) Value> 0}
~~~
它返回了一個對象方法的信息集合即Method,關于Method結構定義在reflect/type.go下具體為:
~~~
// Method represents a single method.
type Method struct {
// Name is the method name.
// PkgPath is the package path that qualifies a lower case (unexported)
// method name. It is empty for upper case (exported) method names.
// The combination of PkgPath and Name uniquely identifies a method
// in a method set.
// See http://golang.org/ref/spec#Uniqueness_of_identifiers
Name string
PkgPath string
Type Type // method type
Func Value // func with receiver as first argument
Index int // index for Type.Method
}
~~~
### 通過reflect.ValueOf(i)獲取對象方法的信息
~~~
vMethod := v.MethodByName("Init")
fmt.Println(vMethod)
~~~
### 通過reflect.ValueOf(i)調用方法
~~~
package main
import (
"reflect"
"fmt"
)
type ControllerInterface interface {
Init(action string, method string)
}
type Controller struct {
Action string
Method string
Tag string `json:"tag"`
}
func (c *Controller) Init(action string, method string){
c.Action = action
c.Method = method
//增加fmt打印,便于看是否調用
fmt.Println("Init() is run.")
fmt.Println("c:",c)
}
//增加一個無參數的Func
func (c *Controller) Test(){
fmt.Println("Test() is run.")
}
func main(){
//初始化
runController := &Controller{
Action:"Run1",
Method:"GET",
}
//Controller實現了ControllerInterface方法,因此它就實現了ControllerInterface接口
var i ControllerInterface
i = runController
// 得到實際的值,通過v我們獲取存儲在里面的值,還可以去改變值
v := reflect.ValueOf(i)
fmt.Println("value:",v)
// 有輸入參數的方法調用
// 構造輸入參數
args1 := []reflect.Value{reflect.ValueOf("Run2"),reflect.ValueOf("POST")}
// 通過v進行調用
v.MethodByName("Init").Call(args1)
// 無輸入參數的方法調用
// 構造zero value
args2 := make([]reflect.Value, 0)
// 通過v進行調用
v.MethodByName("Test").Call(args2)
}
~~~
~~~
打印結果:
value: &{Run1 GET }
//有參數的Func
Init() is run.
c: &{Run2 POST }
//無參數的Func
Test() is run.
~~~
# 從反射對象到接口值的反射
# 修改反射對象
最近在寫ATC框架,路由第一版構思中用到了反射就整理了下,不過經過幾個莫名夜晚糾結,最終第二版構思實踐中又把所有反射干掉了(淚…, 討論群中一致認為反射對性能影響較大,能避免則避免,不能避免就少用。),目前思路和框架已定型,一個輕量級簡單的RESTful go 框架 即將發布…
不早了,先到這里吧,米西米西了。空了在補充,還有很多反射內容待進一步完善……
有空的話就把beego框架中用到的反射知識整理分享下,利己利人。
# 參考資料
示例代碼:
[https://github.com/lxmgo/learngo/blob/master/reflect/reflect.go](https://github.com/lxmgo/learngo/blob/master/reflect/reflect.go)
- 前言
- golang學習(一)之安裝
- Go語言學習二:Go基礎(變量、常量、數值類型、字符串、錯誤類型)
- Go語言學習三:Go基礎(iota,array,slice,map,make,new)
- Go語言學習四:struct類型
- Ubuntu 14.04/CentOS 6.5中安裝GO LANG(GO語言)
- Mac OS 安裝golang
- Mac install Thrift
- Thrift RPC 使用指南實戰(附golang&amp;PHP代碼)
- golang net/http包使用
- 冒泡排序Bubble sort-golang
- 快速排序Quick sort - golang
- Go語言學習:Channel是什么?
- Golang的select/非緩沖的Channel實例詳解
- Golang time包的定時器/斷續器
- Golang同步:鎖的使用案例詳解
- Golang同步:條件變量和鎖組合使用
- Golang同步:原子操作使用
- Golang之bytes.buffer
- Golang之字符串格式化
- Golang之反射reflect包
- Go語言配置文件解析器,類似于Windows下的INI文件.