W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
原文鏈接:https://gopl-zh.github.io/ch12/ch12-09.html
雖然反射提供的API遠多于我們講到的,我們前面的例子主要是給出了一個方向,通過反射可以實現(xiàn)哪些功能。反射是一個強大并富有表達力的工具,但是它應(yīng)該被小心地使用,原因有三。
第一個原因是,基于反射的代碼是比較脆弱的。對于每一個會導致編譯器報告類型錯誤的問題,在反射中都有與之相對應(yīng)的誤用問題,不同的是編譯器會在構(gòu)建時馬上報告錯誤,而反射則是在真正運行到的時候才會拋出panic異常,可能是寫完代碼很久之后了,而且程序也可能運行了很長的時間。
以前面的readList函數(shù)(§12.6)為例,為了從輸入讀取字符串并填充int類型的變量而調(diào)用的reflect.Value.SetString方法可能導致panic異常。絕大多數(shù)使用反射的程序都有類似的風險,需要非常小心地檢查每個reflect.Value的對應(yīng)值的類型、是否可取地址,還有是否可以被修改等。
避免這種因反射而導致的脆弱性的問題的最好方法,是將所有的反射相關(guān)的使用控制在包的內(nèi)部,如果可能的話避免在包的API中直接暴露reflect.Value類型,這樣可以限制一些非法輸入。如果無法做到這一點,在每個有風險的操作前指向額外的類型檢查。以標準庫中的代碼為例,當fmt.Printf收到一個非法的操作數(shù)時,它并不會拋出panic異常,而是打印相關(guān)的錯誤信息。程序雖然還有BUG,但是會更加容易診斷。
fmt.Printf("%d %s\n", "hello", 42) // "%!d(string=hello) %!s(int=42)"
反射同樣降低了程序的安全性,還影響了自動化重構(gòu)和分析工具的準確性,因為它們無法識別運行時才能確認的類型信息。
避免使用反射的第二個原因是,即使對應(yīng)類型提供了相同文檔,但是反射的操作不能做靜態(tài)類型檢查,而且大量反射的代碼通常難以理解。總是需要小心翼翼地為每個導出的類型和其它接受interface{}或reflect.Value類型參數(shù)的函數(shù)維護說明文檔。
第三個原因,基于反射的代碼通常比正常的代碼運行速度慢一到兩個數(shù)量級。對于一個典型的項目,大部分函數(shù)的性能和程序的整體性能關(guān)系不大,所以當反射能使程序更加清晰的時候可以考慮使用。測試是一個特別適合使用反射的場景,因為每個測試的數(shù)據(jù)集都很小。但是對于性能關(guān)鍵路徑的函數(shù),最好避免使用反射。
![]() | ![]() |
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: