理解golang反射(reflection in Go)

來源:互聯網
上載者:User

反射(reflection)是指在運行時,動態擷取程式結構資訊(元資訊)的一種能力,是靜態類型語言都支援的一種特性,如Java, golang等。這裡主要詳細介紹golang reflection相關知識

類型與介面(Types and interfaces)

type MyInt intvar i intvar j MyInt

i 為int類型,j為MyInt類型。雖然i,j底層類型均為int,但它們屬於不同類型,沒有轉換不能相互賦值。

介面類型 interface, 表示一系列方法集合,任意concrete (non-interface) value 只要實現了介面方法,便可賦值給interface

// Reader is the interface that wraps the basic Read method.type Reader interface {    Read(p []byte) (n int, err error)}// Writer is the interface that wraps the basic Write method.type Writer interface {    Write(p []byte) (n int, err error)}var r io.Readerr = os.Stdinr = bufio.NewReader(r)r = new(bytes.Buffer)// and so on

r變數的靜態類型為io.Reader,實際類型可能是File, Buffer類型

interface{} 特殊介面類型,沒有任何方法,因此任何類型都可賦值給它

The representation of an interface

var r io.Readerr = new(bytes.Buffer)

r變數的具體類型是io.Reader,實際類型是bytes.Buffer,那麼在運行時,golang是如何?的呢?

一個interface類型的變數儲存了2個資訊, 一個值,類型對<value,type> pair:

  • 賦給變數的值(concrete value)

  • 變數值的類型描述元(value's type descriptor)

var r io.Readertty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)if err != nil {    return nil, err}r = tty

介面類型r 的<value, type> pair是(tty*os.File)

當然r變數的value tty不僅僅實現了io.Reader介面中的Read方法,還實現了io.Writer中的Write方法,因此可以進行

類型斷言(type assertion),試圖將r 轉換為io.Writer

var w io.Writerw = r.(io.Writer)

此時,介面變數w的<value,type>pair 為 (tty*os.File),也就是說r,w 底層value是一樣的,可以通過不同的type來暴露不同的方法出來。

繼續討論

var empty interface{}empty = w //此處不需要type assertion,因為任意類型都可以看作實現了empty interface的方法

介面變數empty的<value,type> pair 為 (tty*os.File)

Reflection

1. Reflection goes from interface value to reflection object.(介面類型---> 反射類型(reflect.Value,reflect.Type))

反射,可以擷取interface類型變數的具體資訊(<value,concrete type>)

golang 反射包為reflect

// 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 //擷取pair中的value// 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   //擷取pair中的concrete type

eg:

var r io.Readerr = os.Stdin   // <value, type> : <os.Stdin, *os.File>rValue := reflect.ValueOf(r)rType  := reflect.TypeOf(r)fmt.Println("value:", rValue)fmt.Println("type :", rType)輸出:value: &{0xc04205a000} //指標type : *os.Filevar f float64f = 1.234fmt.Println("f value:",reflect.ValueOf(f))fmt.Println("f type :",reflect.TypeOf(f))輸出:f value: 1.234f type : float64

2. Reflection goes from reflection object to interface value. 反射類型(reflect.Value,reflect.Type) --> 介面類型

type User struct {   Id   int   Name string   Age  int}func (u User) ReflectCallFunc() {   fmt.Println("reflect learn")}user := User{1, "test", 13}var i interface{}i = useruValue := reflect.ValueOf(i)uType  := reflect.TypeOf(i)fmt.Println("uValue: ",uValue)fmt.Println(uValue.Interface()) //轉換為interface類型,unpack uValue.Interface().(User)fmt.Println(uValue.Type())fmt.Println("uValue,string: ",uType.String())fmt.Println("uType: ",uType.Name())for i := 0; i < uType.NumField(); i++ { //擷取field資訊   field := uType.Field(i)   value := uValue.Field(i).Interface()   fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)}for i := 0; i < uType.NumMethod(); i++ {// 擷取method資訊   method := uType.Method(i)    fmt.Printf("method[%d] = %s \n",i,method.Name)}fmt.Println(uValue.Kind())fmt.Println(uType.Kind())


3. To modify a reflection object, the value must be settable. 通過反射修改變數

var x float64 = 3.4v := reflect.ValueOf(x)fmt.Println("settability of v:", v.CanSet()) //print: settability of v: falsev.SetFloat(7.1) // Error: will panic.

不可修改的原因:we pass a copy of x to reflect.ValueOf, so the interface value created as the argument to reflect.ValueOf is a copy of x, not x itself

解決辦法,傳遞指標!!

var x float64 = 3.4p := reflect.ValueOf(&x) // Note: take the address of x.fmt.Println("type of p:", p.Type())fmt.Println("settability of p:", p.CanSet())print:type of p: *float64settability of p: false //why ? p不可set,p指向的內容可set,p指向的內容即*p,如何獲得p指向的內容?

reflect.Value 的Elem方法,可以擷取value 指向的內容

v := p.Elem()fmt.Println("settability of v:", v.CanSet())//settability of v: truev.SetFloat(7.1)fmt.Println(v.Interface()) //7.1fmt.Println(x)             //7.1


4. Structs 反射操作執行個體

type T struct {   A int   B string}t := T{23, "skidoo"}s := reflect.ValueOf(&t).Elem()typeOfT := s.Type()for i := 0; i < s.NumField(); i++ {   f := s.Field(i)   fmt.Printf("%d:%v %s %s = %v\n", i, s.Kind(), typeOfT.Field(i).Name, f.Type(), f.Interface())}fmt.Println("canSet:",s.CanSet())s.Field(0).SetInt(24)s.Field(1).SetString("Sunset Strip")fmt.Println("after change: ",s.Interface())

5. 通過reflect 來調用方法

type User struct {   Id   int   Name string   Age  int}func (u User) ReflectCallFunc() {   fmt.Println("reflect learn")}func (u User) FuncHasArgs(name string, age int) {   fmt.Println("FuncHasArgs name: ", name, ", age:", age, "and origal User.Name:", u.Name)}func (u User) FuncNoArgs() {   fmt.Println("FuncNoArgs")}user := User{1, "test", 13}uValue := reflect.ValueOf(user)uType  := reflect.TypeOf(user)m1 := uValue.MethodByName("FuncHasArgs")m2 := uValue.MethodByName("FuncNoArgs")m ,b := uType.MethodByName("FuncNoArgs")args := []reflect.Value{reflect.ValueOf("xiong"), reflect.ValueOf(30)}m1.Call(args)args = make([]reflect.Value,0)m2.Call(args)fmt.Println("m1:",m1)fmt.Println("m2:",m2)fmt.Printf("m:%#v,isfound:%v\n",m,b)fmt.Println(m1)



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.