update tw

This commit is contained in:
chai2010
2015-12-18 10:53:03 +08:00
parent 510c741a6f
commit c66a96ee52
106 changed files with 864 additions and 864 deletions

View File

@@ -1,11 +1,11 @@
## 12.1. 何需要反射?
## 12.1. 何需要反射?
有時候我們需要編寫一函數能夠處理一類不滿足普通公共接口的類型的值, 也可能它們沒有確定的示方式, 或者在我們設計該函數的時候還這些類型可能還不存在, 各種情況都有可能.
有時候我們需要編寫一函數能夠處理一類不滿足普通公共接口的類型的值, 也可能它們沒有確定的示方式, 或者在我們設計該函數的時候還這些類型可能還不存在, 各種情況都有可能.
大傢熟悉的例子是 fmt.Fprintf 函數提供的字符串格式化處理邏輯, 它可以用例對任意類型的值格式化打印, 甚至是用戶自定義的類型. 讓我們來嘗試實現一類似功能的函數. 簡單起見, 我們的函數隻接收一參數, 然後返迴和 fmt.Sprint 類似的格式化後的字符串, 我們的函數名也叫 Sprint.
大傢熟悉的例子是 fmt.Fprintf 函數提供的字符串格式化處理邏輯, 它可以用例對任意類型的值格式化打印, 甚至是用戶自定義的類型. 讓我們來嘗試實現一類似功能的函數. 簡單起見, 我們的函數隻接收一參數, 然後返迴和 fmt.Sprint 類似的格式化後的字符串, 我們的函數名也叫 Sprint.
我們使用了 switch 分支首先來測試輸入參數是否實現了 String 方法, 如果是的話就使用該方法. 然後繼續增加測試分支, 檢査是否是每基於 string, int, bool 等基礎類型的動態類型, 在每種情況下執行適的格式化操作.
我們使用了 switch 分支首先來測試輸入參數是否實現了 String 方法, 如果是的話就使用該方法. 然後繼續增加測試分支, 檢査是否是每基於 string, int, bool 等基礎類型的動態類型, 在每種情況下執行適的格式化操作.
```Go
func Sprint(x interface{}) string {
@@ -32,8 +32,8 @@ func Sprint(x interface{}) string {
}
```
但是我們如何處理其它類似 []float64, map[string][]string 等類型呢? 我們然可以添加更多的測試分支, 但是這些組類型的數目基本是無窮的. 還有如何處理 url.Values 等命令的類型呢? 雖然類型分支可以識別齣底層的基礎類型是 map[string][]string, 但是它不匹配 url.Values 類型, 因爲這是兩種不的類型, 而且 switch 分支也不可能包含每類似 url.Values 的類型, 這會導緻對這些庫的依賴.
但是我們如何處理其它類似 []float64, map[string][]string 等類型呢? 我們然可以添加更多的測試分支, 但是這些組類型的數目基本是無窮的. 還有如何處理 url.Values 等命令的類型呢? 雖然類型分支可以識別齣底層的基礎類型是 map[string][]string, 但是它不匹配 url.Values 類型, 因爲這是兩種不的類型, 而且 switch 分支也不可能包含每類似 url.Values 的類型, 這會導緻對這些庫的依賴.
沒有一種方法來檢査未知類型的示方式, 我們被卡住了. 這就是我們爲何需要反射的原因.
沒有一種方法來檢査未知類型的示方式, 我們被卡住了. 這就是我們爲何需要反射的原因.

View File

@@ -1,9 +1,9 @@
## 12.2. reflect.Type和reflect.Value
反射是由 reflect 包提供支持. 它定義了兩重要的類型, Type 和 Value. 一 Type 示一Go類型. 它是一接口, 有許多方法來區分類型和檢査它們的組件, 例如一結構體的成員或一函數的參數等. 唯一能反映 reflect.Type 實現的是接口的類型描述信息(§7.5), 樣的實體標識了動態類型的接口值.
反射是由 reflect 包提供支持. 它定義了兩重要的類型, Type 和 Value. 一 Type 示一Go類型. 它是一接口, 有許多方法來區分類型和檢査它們的組件, 例如一結構體的成員或一函數的參數等. 唯一能反映 reflect.Type 實現的是接口的類型描述信息(§7.5), 樣的實體標識了動態類型的接口值.
函數 reflect.TypeOf 接受任意的 interface{} 類型, 返迴對應動態類型的reflect.Type:
函數 reflect.TypeOf 接受任意的 interface{} 類型, 返迴對應動態類型的reflect.Type:
```Go
t := reflect.TypeOf(3) // a reflect.Type
@@ -11,22 +11,22 @@ fmt.Println(t.String()) // "int"
fmt.Println(t) // "int"
```
其中 TypeOf(3) 調用將值 3 作爲 interface{} 類型參數傳入. 迴到 7.5節 的將一具體的值轉爲接口類型會有一隱式的接口轉換操作, 它會創建一包含兩信息的接口值: 操作數的動態類型(這裡是int)和它的動態的值(這裡是3).
其中 TypeOf(3) 調用將值 3 作爲 interface{} 類型參數傳入. 迴到 7.5節 的將一具體的值轉爲接口類型會有一隱式的接口轉換操作, 它會創建一包含兩信息的接口值: 操作數的動態類型(這裡是int)和它的動態的值(這裡是3).
因爲 reflect.TypeOf 返迴的是一動態類型的接口值, 它總是返迴具體的類型. 因此, 下的代碼將打印 "*os.File" 而不是 "io.Writer". 稍後, 我們將看到 reflect.Type 是具有識別接口類型的達方式功能的.
因爲 reflect.TypeOf 返迴的是一動態類型的接口值, 它總是返迴具體的類型. 因此, 下的代碼將打印 "*os.File" 而不是 "io.Writer". 稍後, 我們將看到 reflect.Type 是具有識別接口類型的達方式功能的.
```Go
var w io.Writer = os.Stdout
fmt.Println(reflect.TypeOf(w)) // "*os.File"
```
要註意的是 reflect.Type 接口是滿足 fmt.Stringer 接口的. 因爲打印動態類型值對於調試和日誌是有幫助的, fmt.Printf 提供了一簡短的 %T 標誌參數, 內部使用 reflect.TypeOf 的結果輸齣:
要註意的是 reflect.Type 接口是滿足 fmt.Stringer 接口的. 因爲打印動態類型值對於調試和日誌是有幫助的, fmt.Printf 提供了一簡短的 %T 標誌參數, 內部使用 reflect.TypeOf 的結果輸齣:
```Go
fmt.Printf("%T\n", 3) // "int"
```
reflect 包中另一重要的類型是 Value. 一 reflect.Value 可以持有一任意類型的值. 函數 reflect.ValueOf 接受任意的 interface{} 類型, 返迴對應動態類型的reflect.Value. 和 reflect.TypeOf 類似, reflect.ValueOf 返迴的結果也是對於具體的類型, 但是 reflect.Value 也可以持有一接口值.
reflect 包中另一重要的類型是 Value. 一 reflect.Value 可以持有一任意類型的值. 函數 reflect.ValueOf 接受任意的 interface{} 類型, 返迴對應動態類型的reflect.Value. 和 reflect.TypeOf 類似, reflect.ValueOf 返迴的結果也是對於具體的類型, 但是 reflect.Value 也可以持有一接口值.
```Go
v := reflect.ValueOf(3) // a reflect.Value
@@ -35,7 +35,7 @@ fmt.Printf("%v\n", v) // "3"
fmt.Println(v.String()) // NOTE: "<int Value>"
```
和 reflect.Type 類似, reflect.Value 也滿足 fmt.Stringer 接口, 但是除非 Value 持有的是字符串, 否則 String 隻是返迴具體的類型. 相, 使用 fmt 包的 %v 標誌參數, 將使用 reflect.Values 的結果格式化.
和 reflect.Type 類似, reflect.Value 也滿足 fmt.Stringer 接口, 但是除非 Value 持有的是字符串, 否則 String 隻是返迴具體的類型. 相, 使用 fmt 包的 %v 標誌參數, 將使用 reflect.Values 的結果格式化.
調用 Value 的 Type 方法將返迴具體類型所對應的 reflect.Type:
@@ -44,7 +44,7 @@ t := v.Type() // a reflect.Type
fmt.Println(t.String()) // "int"
```
逆操作是調用 reflect.ValueOf 對應的 reflect.Value.Interface 方法. 它返迴一 interface{} 類型示 reflect.Value 對應類型的具體值:
逆操作是調用 reflect.ValueOf 對應的 reflect.Value.Interface 方法. 它返迴一 interface{} 類型示 reflect.Value 對應類型的具體值:
```Go
v := reflect.ValueOf(3) // a reflect.Value
@@ -53,9 +53,9 @@ i := x.(int) // an int
fmt.Printf("%d\n", i) // "3"
```
reflect.Value 和 interface{} 都能保存任意的值. 所不的是, 一空的接口隱藏了值對應的示方式和所有的公開的方法, 因此隻有我們知道具體的動態類型纔能使用類型斷言來訪問內部的值(就像上那樣), 對於內部值沒有特別可做的事情. 相比之下, 一 Value 則有很多方法來檢査其內容, 無論它的具體類型是什. 讓我們再次嘗試實現我們的格式化函數 format.Any.
reflect.Value 和 interface{} 都能保存任意的值. 所不的是, 一空的接口隱藏了值對應的示方式和所有的公開的方法, 因此隻有我們知道具體的動態類型纔能使用類型斷言來訪問內部的值(就像上那樣), 對於內部值沒有特別可做的事情. 相比之下, 一 Value 則有很多方法來檢査其內容, 無論它的具體類型是什. 讓我們再次嘗試實現我們的格式化函數 format.Any.
我們使用 reflect.Value 的 Kind 方法來替代之前的類型 switch. 雖然還是有無窮多的類型, 但是它們的kinds類型卻是有限的: Bool, String 和 所有數字類型的基礎類型; Array 和 Struct 對應的聚類型; Chan, Func, Ptr, Slice, 和 Map 對應的引用類似; 接口類型; 還有示空值的無效類型. (空的 reflect.Value 對應 Invalid 無效類型.)
我們使用 reflect.Value 的 Kind 方法來替代之前的類型 switch. 雖然還是有無窮多的類型, 但是它們的kinds類型卻是有限的: Bool, String 和 所有數字類型的基礎類型; Array 和 Struct 對應的聚類型; Chan, Func, Ptr, Slice, 和 Map 對應的引用類似; 接口類型; 還有示空值的無效類型. (空的 reflect.Value 對應 Invalid 無效類型.)
```Go
gopl.io/ch12/format
@@ -96,7 +96,7 @@ func formatAtom(v reflect.Value) string {
}
```
到目前未知, 我們的函數將每值視作一不可分割沒有內部結構的, 因此它叫 formatAtom. 對於聚類型(結構體和數組)接口隻是打印類型的值, 對於引用類型(channels, functions, pointers, slices, 和 maps), 它十六進製打印類型的引用地址. 雖然還不夠理想, 但是依然是一重大的進步, 且 Kind 隻關心底層示, format.Any 也支持新命名的類型. 例如:
到目前未知, 我們的函數將每值視作一不可分割沒有內部結構的, 因此它叫 formatAtom. 對於聚類型(結構體和數組)接口隻是打印類型的值, 對於引用類型(channels, functions, pointers, slices, 和 maps), 它十六進製打印類型的引用地址. 雖然還不夠理想, 但是依然是一重大的進步, 且 Kind 隻關心底層示, format.Any 也支持新命名的類型. 例如:
```Go
var x int64 = 1

View File

@@ -1,3 +1,3 @@
## 12.6. 示例: 解碼S達式
## 12.6. 示例: 解碼S達式
TODO

View File

@@ -1,3 +1,3 @@
## 12.7. 取結構體字段標識
## 12.7. 取結構體字段標識
TODO

View File

@@ -1,6 +1,6 @@
# 第十二章 反射
Go提供了一種機製在運行時更新變量和檢査它們的值, 調用它們的方法, 和它們支持的內在操作, 但是在編譯時不知道這些變量的類型. 這種機製被稱爲反射. 反射也可以讓我們將類型本身作爲第一類的值類型處理.
Go提供了一種機製在運行時更新變量和檢査它們的值, 調用它們的方法, 和它們支持的內在操作, 但是在編譯時不知道這些變量的類型. 這種機製被稱爲反射. 反射也可以讓我們將類型本身作爲第一類的值類型處理.
在本章, 我們將探討Go語言的反射特性, 看看它可以給語言增加哪些達力, 以及在兩至關重要的API是如何用反射機製的: 一是 fmt 包提供的字符串格式功能, 另一是類似 encoding/json 和 encoding/xml 提供的鍼對特定協議的編解碼功能. 對於我們在4.6節中看到過的 text/template 和 html/template 包, 它們的實現也是依賴反射技術的. 然後, 反射是一復雜的內省技術, 而應該隨意使用, 因此, 管上這些包都是用反射技術實現的, 但是它們自己的API都沒有公開反射相關的接口.
在本章, 我們將探討Go語言的反射特性, 看看它可以給語言增加哪些達力, 以及在兩至關重要的API是如何用反射機製的: 一是 fmt 包提供的字符串格式功能, 另一是類似 encoding/json 和 encoding/xml 提供的鍼對特定協議的編解碼功能. 對於我們在4.6節中看到過的 text/template 和 html/template 包, 它們的實現也是依賴反射技術的. 然後, 反射是一復雜的內省技術, 而應該隨意使用, 因此, 管上這些包都是用反射技術實現的, 但是它們自己的API都沒有公開反射相關的接口.