若是傳入的是一個接口,若是是動態綁定了一個實現結構體的,則顯示具體結構體的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 性能
爲何要字節對齊?ui
加快訪問速度,減小讀取次數。若是不對齊,那麼一個數據的地址可能會分散到用兩個字節,那麼CPU就可能須要分兩次讀取。this
咱們假設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
part2
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?上圖 }
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.
反射方法。第一個傳入0 1 2來表示方法 後面那個傳入字符串
反射屬性,Tag屬性能夠得到屬性後面的註解調用Get方法
這是一個結構體,能夠操做對象的值,每一個方法都返回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 }
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類型
要修改對象的值,必須指針的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
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