[go]反射

1、reflect.Typeof()

若是傳入的是一個接口,若是是動態綁定了一個實現結構體的,則顯示具體結構體的Type,不然是接口的名字。這個方法返回的是一個Type接口,其實就是返回了 綁定類型的rtype,這個指針在Value這個結構體有json

a:=A{}
a.age=19
a.name="PB"
i:=1
log.Println(reflect.TypeOf(a).Name()) //類型的名字  A	
log.Println(reflect.TypeOf(i).Name()) //int


//底層基礎類型
log.Println(reflect.TypeOf(a).Kind(),reflect.TypeOf(i).Kind()) //struct int
log.Println(reflect.TypeOf(a).Kind().String()=="struct") //true  
//返回的是Kind類型  須要經過string轉化 不然是一個uint類型

Typeof返回的是一個Type接口下面看看Type接口有哪些實現函數

type Student struct {
	name string `pb:"名字"`
	age  int    `json:"年齡"`
}

type Part1 struct {
	a bool
	b int32 //4 byte
	c int8
	d int64
	e byte
}
type Part2 struct {
	e byte
	c int8
	a bool
	b int32
	d int64
}

利用反射能夠查看結構體或其餘類型的內存分配狀況,如內存大小,字節對齊的大小等....佈局

http://www.fly63.com/article/detial/7405 性能

Size():關於內存

爲何要字節對齊?ui

加快訪問速度,減小讀取次數。若是不對齊,那麼一個數據的地址可能會分散到用兩個字節,那麼CPU就可能須要分兩次讀取。this

img

咱們假設CPU以4字節爲單位讀取內存。指針

若是變量在內存中的佈局按4字節對齊,那麼讀取a變量只須要讀取一次內存,即word1;讀取b變量也只須要讀取一次內存,即word2。code

而若是變量不作內存對齊,那麼讀取a變量也只須要讀取一次內存,即word1;可是讀取b變量時,因爲b變量跨越了2個word,因此須要讀取兩次內存,分別讀取word1和word2的值,而後將word1偏移取後3個字節,word2偏移取前1個字節,最後將它們作或操做,拼接獲得b變量的值。orm

顯然,內存對齊在某些狀況下能夠減小讀取內存的次數以及一些運算,性能更高。對象

另外,因爲內存對齊保證了讀取b變量是單次操做,在多核環境下,原子性更容易保證。

可是內存對齊提高性能的同時,也須要付出相應的代價。因爲變量與變量之間增長了填充,並無存儲真實有效的數據,因此佔用的內存會更大。這也是一個典型的空間換時間的應用場景。

  • 增長CPU吞吐量,減小讀取次數
  • 保證原子操做
  • 空間換時間,若是沒有安排好內存的話,中間會多出不少空白

part1

img

part2

img

func main(){
    s1 := Student{"pb", 12}
	type_s1 := reflect.TypeOf(s1) 
	type_part1 := reflect.TypeOf(Part1{})
	type_part2 := reflect.TypeOf(Part2{})
    
    //關於內存
	log.Println(type_s1.Align(), type_part1.Align()) //8 8
	log.Println(type_s1.FieldAlign(), type_part1.FieldAlign()) //8 8
    
	log.Println(type_part1.Size(), type_part2.Size()) //32 16 why?上圖
}


Key() Elem()
type MyMap map[int]string
log.Println(reflect.TypeOf(MyMap{}).Key()) //返回map類型 key的類型 int
log.Println(reflect.TypeOf(MyMap{}).Elem()) //返回 容器類型中元素的類型  string
//It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.


Method() MethodByName()

反射方法。第一個傳入0 1 2來表示方法 後面那個傳入字符串

FieldByXXXX()

反射屬性,Tag屬性能夠得到屬性後面的註解調用Get方法





2、reflect.Valueof()

這是一個結構體,能夠操做對象的值,每一個方法都返回Value來達到鏈式調用的目的,

Type能實現的功能Value均可以

type Value struct {
	typ *rtype //Typeof返回的東西  繼承了Type接口 保存了一個數據的類型和底層指針
	ptr unsafe.Pointer
	flag
}

type rtype struct {
	size       uintptr
	ptrdata    uintptr  // number of bytes in the type that can contain pointers
	hash       uint32   // hash of type; avoids computation in hash tables
	tflag      tflag    // extra type information flags
	align      uint8    // alignment of variable with this type
	fieldAlign uint8    // alignment of struct field with this type
	kind       uint8    // enumeration for C
	alg        *typeAlg // algorithm table
	gcdata     *byte    // garbage collection data
	str        nameOff  // string form
	ptrToThis  typeOff  // type for pointer to this type, may be zero
}
Method()
type Stu struct {
	name string "名字"
	age  int    "年齡"
}

func (s *Stu) Say()  {
	fmt.Println(s.name)
}

func (s Stu) Hello()  {
	fmt.Println(s.name)
}
func (s Stu) Hello2(ss string,i int)  {
	fmt.Println(ss,i)
}
s := Stu{"pb", 12}
v := reflect.ValueOf(s)

fmt.Println(v,v.Field(0))
fmt.Println(v.Kind(), v.Type().Name())
fmt.Println(v.FieldByName("name"), v.Field(0))

	//操做方法  方法位置按照函數名字進行字典序排序
v.Method(0).Call(nil)                              //#調用無參函數
v.Method(1).Call([]reflect.Value{reflect.ValueOf("OK"), reflect.ValueOf(1)}) //#調用有參函數 必須是Value類型


Elem()

要修改對象的值,必須指針的Value調用Elem方法才能夠修改

只能指針的Value(包括動態綁定的接口,若是這個接口的值是指針類型也可)才能夠調用而且修改原來對象的值

s = Stu{Name:"biningo",age:18}
sv:=reflect.ValueOf(s)
log.Println(sv.Field(0))

pv:=reflect.ValueOf(&s)

//// It panics if v's Kind is not Interface or Ptr.
//log.Println(reflect.ValueOf(s).Elem().CanSet())  
log.Println(pv.Elem().Field(0),pv.Elem().Field(0).CanSet()) //biningo true
pv.Elem().Field(0).SetString("BININGO") 
log.Println(pv.Elem().Field(1).CanSet()) //false 必需要大寫的字段才能夠設置

log.Println(s) //BININGO 18


//對於沒有接口的類型來講 返回的就是一個指針
i:=pv.Interface() //返回空接口
//Valueof返回的是實際動態綁定的類型 這裏是*Stu
log.Println(reflect.ValueOf(i).Elem().CanSet()) //true  若是不加Elem則false





3、Value和Type相互轉換

Type和Value能夠相互轉化

經過Type來建立一個Value

t:=sv.Type() //Value->Type
log.Println(t.Name()) //Stu

//Type建立Value
s2:=reflect.New(t)
log.Println(s2.Type(),s2.Elem().CanSet(),s2) //true由於返回的是*Stu 都是默認值
s2.Elem().Field(0).SetString("Biningo2")
//s2.Elem().Field(1).SetInt(19) 私有字段不可設置
log.Println(s2)

Value能夠直接轉化爲Type

調用Value的Type方法便可

Value轉化爲具體對象

Value-->Interface-->Obj

//Value轉化爲具體對象
//Value-->Interface-->Obj
inter:=sv.Interface() //*Stu
s1:=inter.(Stu)
log.Println(s1) // biningo 18
相關文章
相關標籤/搜索