網站首頁 編程語言 正文
引言
這算是一個高級用法了,前面我們只說到對類型、變量的幾種反射的用法,包括如何獲取其值、其類型、以及如何重新設置新值。但是在項目應用中,另外一個常用并且屬于高級的用法,就是通過reflect來進行方法【函數】的調用。比如我們要做框架工程的時候,需要可以隨意擴展方法,或者說用戶可以自定義方法,那么我們通過什么手段來擴展讓用戶能夠自定義呢?關鍵點在于用戶的自定義方法是未可知的,因此我們可以通過reflect來搞定。
func (Value)?Call
func (v Value) Call(in []Value) []Value
Call方法使用輸入的參數in調用v持有的函數。例如,如果len(in) == 3,v.Call(in)代表調用v(in[0], in[1], in[2])(其中Value值表示其持有值)。如果v的Kind不是Func會panic。它返回函數所有輸出結果的Value封裝的切片。和go代碼一樣,每一個輸入實參的持有值都必須可以直接賦值給函數對應輸入參數的類型。如果v持有值是可變參數函數,Call方法會自行創建一個代表可變參數的切片,將對應可變參數的值都拷貝到里面。
通過反射,調用方法。
先獲取結構體對象,然后調用結構體的方法。
示例代碼:
package main import ( "fmt" "reflect" ) type Person struct { Name string Age int Sex string } func (p Person)Say(msg string) { fmt.Println("hello,",msg) } func (p Person)PrintInfo() { fmt.Printf("姓名:%s,年齡:%d,性別:%s\n",p.Name,p.Age,p.Sex) } func (p Person) Test(i,j int,s string){ fmt.Println(i,j,s) } // 如何通過反射來進行方法的調用? // 本來可以用結構體對象.方法名稱()直接調用的, // 但是如果要通過反射, // 那么首先要將方法注冊,也就是MethodByName,然后通過反射調動mv.Call func main() { p2 := Person{"王富貴",20,"男"} // 1. 要通過反射來調用起對應的方法,必須要先通過reflect.ValueOf(interface)來獲取到reflect.Value, // 得到“反射類型對象”后才能做下一步處理 getValue := reflect.ValueOf(p2) // 2.一定要指定參數為正確的方法名 // 先看看沒有參數的調用方法 methodValue1 := getValue.MethodByName("PrintInfo") fmt.Printf("Kind : %s, Type : %s\n",methodValue1.Kind(),methodValue1.Type()) methodValue1.Call(nil) //沒有參數,直接寫nil args1 := make([]reflect.Value, 0) //或者創建一個空的切片也可以 methodValue1.Call(args1) // 有參數的方法調用 methodValue2 := getValue.MethodByName("Say") fmt.Printf("Kind : %s, Type : %s\n",methodValue2.Kind(),methodValue2.Type()) args2 := []reflect.Value{reflect.ValueOf("反射機制")} methodValue2.Call(args2) methodValue3 := getValue.MethodByName("Test") fmt.Printf("Kind : %s, Type : %s\n",methodValue3.Kind(),methodValue3.Type()) args3 := []reflect.Value{reflect.ValueOf(5), reflect.ValueOf(2),reflect.ValueOf("you")} methodValue3.Call(args3) }
運行結果:
Kind : func, Type : func()
姓名:王富貴,年齡:20,性別:男
姓名:王富貴,年齡:20,性別:男
Kind : func, Type : func(string)
hello, 反射機制
Kind : func, Type : func(int, int, string)
5 2 you
通過反射,調用函數。
首先我們要先確認一點,函數像普通的變量一樣,之前的章節中我們在講到函數的本質的時候,是可以把函數作為一種變量類型的,而且是引用類型。如果說Fun()是一個函數,那么f1 := Fun也是可以的,那么f1也是一個函數,如果直接調用f1(),那么運行的就是Fun()函數。
那么我們就先通過ValueOf()來獲取函數的反射對象,可以判斷它的Kind,是一個func,那么就可以執行Call()進行函數的調用。
示例代碼:
package main import ( "fmt" "reflect" ) func main() { //函數的反射 f1 := fun1 value := reflect.ValueOf(f1) fmt.Printf("Kind : %s , Type : %s\n",value.Kind(),value.Type()) //Kind : func , Type : func() value2 := reflect.ValueOf(fun2) fmt.Printf("Kind : %s , Type : %s\n",value2.Kind(),value2.Type()) //Kind : func , Type : func(int, string) //通過反射調用函數 value.Call(nil) value2.Call([]reflect.Value{reflect.ValueOf("hello"),reflect.ValueOf(61)}) } func fun1(){ fmt.Println("我是函數fun1(),無參的。") } func fun2(s string, i int){ fmt.Println("我是函數fun2(),有參數:",s,i) }
運行結果:
Kind : func , Type : func()
Kind : func , Type : func(string, int)
我是函數fun1(),無參的。
我是函數fun2(),有參數: hello 61
原文鏈接:https://juejin.cn/post/7103368005987336206
相關推薦
- 2022-05-01 skywalking容器化部署docker鏡像構建k8s從測試到可用_docker
- 2022-11-11 python?使用第三方庫requests-toolbelt?上傳文件流的示例_python
- 2021-12-11 關于docker容器部署redis步驟介紹_docker
- 2022-06-17 Android啟動頁設置及動態權限跳轉問題解決_Android
- 2022-06-02 C語言循環隊列與用隊列實現棧問題解析_C 語言
- 2023-02-12 Jupyter?Notebook運行代碼無反應問題及解決方法_python
- 2022-12-29 c#?DataView.ToTable()方法?去除表的重復項問題_C#教程
- 2022-08-23 python文件讀取read及readlines兩種方法使用詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支