反射簡介
反射概述
- 通常的程式邏輯是:編碼時先寫好劇本,執行時按照寫好的劇本演
- 何時建立一個什麼例項,給哪個屬性賦什麼值,然後呼叫它的哪個方法都毫釐不差
- 但能否在執行時動態地生成“劇本”呢?
- 根據具體的業務需要見機行事,動態地生成一個不知道具體型別會是什麼的例項,動態地訪問一個無法提前預知的屬性或方法
- 答案是可以的,這便引出了今天的主角——反射
應用場景舉例:匯出商品列表到Excel
- 需求是:不管使用者在介面上看到什麼商品列表,當它捅一下匯出按鈕,就將該商品的所有屬性和值寫出為檔案;
- 本例的難點是:我們無法預知使用者會選擇匯出什麼型別的商品資料、它有哪些屬性,也就無法相應地去建立Excel資料表的列(讀寫Excel有相應的庫,你也可以選擇寫出為文字檔案、寫出到資料庫表中等等)
- 因為商品的種類太多,如果用正射去做,那麼有多少商品型別我們就要寫多少個switch或if分支,然後在每一個分支里根據當前分支的具體商品型別去構造相應的Excel資料列,這顯然是蹩腳並且很難維護和擴充套件的
- 而通過反射來做就易如反掌了,管你來的是什麼商品例項,立即動態解析得到其類別、所有屬性名值,然後根據屬性名去建立Excel的列,根據屬性值去做資料的填充和寫入
定義結構體
type Human struct {
Name string "姓名"
Age int "年齡"
}
func (h *Human) GetName() string {
fmt.Println("GetName called",h.Name)
return h.Name
}
func (h *Human) SetName(name string) {
fmt.Println("SetName called:", name)
h.Name = name
}
func (h *Human) Eat(food string, grams int) (power int) {
fmt.Println("Eat called:", food, grams)
return 5 * grams
}
反射功能一覽
func main() {
//建立物件(在實際開發中可以是任意未知型別)
h := Human{"bill", 60}
//獲取任意物件的型別和值
getObjTypeValue(h)
//獲得任意物件的所有屬性
getObjFields(h)
//獲取任意物件的所有方法
getObjMethods(&h)
//修改物件任意屬性的值
modifyFieldValue(&h)
//動態呼叫物件的任意方法
callMethods(&h)
fmt.Println("after:h=", h)
}
獲取任意物件的型別和值
func getObjTypeValue(obj interface{}) {
oType := reflect.TypeOf(obj)
oKind := oType.Kind()
fmt.Println(oType, oKind)
oValue := reflect.ValueOf(obj)
fmt.Println(oValue)
}
獲得任意物件的所有屬性
func getObjFields(obj interface{}) {
oType := reflect.TypeOf(obj)
oValue := reflect.ValueOf(obj)
fieldsCount := oType.NumField()
for i := 0; i < fieldsCount; i++ {
//從物件值中獲取第i個屬性的值,進而值的“正射”形式
fValue := oValue.Field(i).Interface()
structField := oType.Field(i)
fmt.Println(structField.Name, structField.Type, structField.Tag, fValue)
}
}
獲取任意物件的所有方法
func getObjMethods(obj interface{}) {
oType := reflect.TypeOf(obj)
fmt.Println(oType.NumMethod())
for i := 0; i < oType.NumMethod(); i++ {
method := oType.Method(i)
fmt.Println(method.Name, method.Type)
}
}
修改物件任意屬性的值
func modifyFieldValue(objPtr interface{}) {
//得到【指標的Value】
oPtrValue := reflect.ValueOf(objPtr)
//得到【指標所指向的值(結構體)的Value】
oValue := oPtrValue.Elem()
fmt.Println(oValue)
//遍歷所有屬性的值
for i := 0; i < oValue.NumField(); i++ {
//根據序號拿到【屬性的Value】
fValue := oValue.Field(i)
//拿到屬性值的原生型別
fKind := fValue.Kind()
//fmt.Println(fKind)
//根據不同的原生型別設定為不同的值
switch fKind {
case reflect.String:
fValue.SetString("張全蛋")
case reflect.Int:
fValue.SetInt(99)
case reflect.Bool:
fValue.SetBool(false)
default:
fmt.Println("設定為其他值...")
}
}
}
動態呼叫物件的任意方法
func callMethods(objPtr interface{}) {
//要通過物件的oType拿取方法的引數列表(oType.In(i))
oType := reflect.TypeOf(objPtr)
//要通過物件的oValue拿取方法的具體實現(methodValue)
oValue := reflect.ValueOf(objPtr)
//根據方法的數量進行遍歷
for i := 0; i < oType.NumMethod(); i++ {
//預定義要傳值的引數切片[]Value
args := make([]reflect.Value, 0)
//從物件的oType拿到當前的方法的methodType
methodType := oType.Method(i).Type
//根據引數個數進行遍歷
//為每個引數亂懟一個同種型別反射值,丟入引數列表
//內層迴圈走完時,當前方法的引數列表就形成了
for j:=0;j<methodType.NumIn();j++{
//從方法的methodType獲取當前引數artType
artType := methodType.In(j)
//再獲取引數型別artType的原生型別
argKind := artType.Kind()
//根據不同的引數原生型別亂懟相同型別的值
switch argKind {
case reflect.String:
//獲取字串"一坨翔"的反射值Value,丟入引數列表
args = append(args,reflect.ValueOf("一坨翔"))
case reflect.Int:
args = append(args,reflect.ValueOf(100))
case reflect.Bool:
args = append(args,reflect.ValueOf(false))
}
}
//從物件值oValue中獲取當前方法值methodValue
methodValue := oValue.Method(i)
//使用引數列表+方法值,反射呼叫當前方法
methodValue.Call(args)
}
}
學院Go語言視訊主頁
https://edu.csdn.net/lecturer/1928
[清華團隊帶你實戰區塊鏈開發]
(https://ke.qq.com/course/344443?tuin=3d17195d)
掃碼獲取海量視訊及原始碼 QQ群:721929980
相關文章
- Java 反射簡介Java反射
- java反射簡解Java反射
- 簡單介紹如何通過註解獲取反射的值反射
- java 反射簡單使用Java反射
- Java反射機制簡答Java反射
- 反射機制的簡答理解反射
- c# 反射專題—————— 介紹一下是什麼是反射[ 一]C#反射
- 第四十九,反射基本介紹反射
- 關於GO反射的簡單定律Go反射
- 簡介
- Jira使用簡介 HP ALM使用簡介
- 一個簡單的反射連線程式反射線程
- BookKeeper 介紹(1)--簡介
- Amphenol簡介
- Vagrant簡介
- PySimpleGUI 簡介GUI
- Protobuf簡介
- MyBatis 簡介MyBatis
- jango簡介Go
- cookie 簡介Cookie
- Session 簡介Session
- Cookie簡介Cookie
- Virgilio 簡介
- Django簡介Django
- ElasticSearch簡介Elasticsearch
- Javascript 簡介JavaScript
- Electron簡介
- Dubbo 簡介
- JavaScript簡介JavaScript
- CSS 簡介CSS
- JanusGraph -- 簡介
- CSS簡介CSS
- Bootstrap 簡介boot
- pwa簡介
- Apache簡介Apache
- JAVA簡介Java
- JUC簡介
- sass簡介