mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-08-11 17:31:44 +00:00
回到简体
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
## 7.13. 類型開關
|
||||
## 7.13. 类型开关
|
||||
|
||||
接口被以兩種不同的方式使用。在第一個方式中,以io.Reader,io.Writer,fmt.Stringer,sort.Interface,http.Handler,和error爲典型,一個接口的方法表達了實現這個接口的具體類型間的相思性,但是隱藏了代表的細節和這些具體類型本身的操作。重點在於方法上,而不是具體的類型上。
|
||||
接口被以两种不同的方式使用。在第一个方式中,以io.Reader,io.Writer,fmt.Stringer,sort.Interface,http.Handler,和error为典型,一个接口的方法表达了实现这个接口的具体类型间的相思性,但是隐藏了代表的细节和这些具体类型本身的操作。重点在于方法上,而不是具体的类型上。
|
||||
|
||||
第二個方式利用一個接口值可以持有各種具體類型值的能力併且將這個接口認爲是這些類型的union(聯合)。類型斷言用來動態地區别這些類型併且對每一種情況都不一樣。在這個方式中,重點在於具體的類型滿足這個接口,而不是在於接口的方法(如果它確實有一些的話),併且沒有任何的信息隱藏。我們將以這種方式使用的接口描述爲discriminated unions(可辨識聯合)。
|
||||
第二个方式利用一个接口值可以持有各种具体类型值的能力并且将这个接口认为是这些类型的union(联合)。类型断言用来动态地区别这些类型并且对每一种情况都不一样。在这个方式中,重点在于具体的类型满足这个接口,而不是在于接口的方法(如果它确实有一些的话),并且没有任何的信息隐藏。我们将以这种方式使用的接口描述为discriminated unions(可辨识联合)。
|
||||
|
||||
如果你熟悉面向對象編程,你可能會將這兩種方式當作是subtype polymorphism(子類型多態)和 ad hoc polymorphism(非參數多態),但是你不需要去記住這些術語。對於本章剩下的部分,我們將會呈現一些第二種方式的例子。
|
||||
如果你熟悉面向对象编程,你可能会将这两种方式当作是subtype polymorphism(子类型多态)和 ad hoc polymorphism(非参数多态),但是你不需要去记住这些术语。对于本章剩下的部分,我们将会呈现一些第二种方式的例子。
|
||||
|
||||
和其它那些語言一樣,Go語言査詢一個SQL數據庫的API會榦淨地將査詢中固定的部分和變化的部分分開。一個調用的例子可能看起來像這樣:
|
||||
和其它那些语言一样,Go语言查询一个SQL数据库的API会干净地将查询中固定的部分和变化的部分分开。一个调用的例子可能看起来像这样:
|
||||
|
||||
```go
|
||||
import "database/sql"
|
||||
@@ -19,7 +19,7 @@ func listTracks(db sql.DB, artist string, minYear, maxYear int) {
|
||||
}
|
||||
```
|
||||
|
||||
Exec方法使用SQL字面量替換在査詢字符串中的每個'?';SQL字面量表示相應參數的值,它有可能是一個布爾值,一個數字,一個字符串,或者nil空值。用這種方式構造査詢可以幫助避免SQL註入攻擊;這種攻擊就是對手可以通過利用輸入內容中不正確的引文來控製査詢語句。在Exec函數內部,我們可能會找到像下面這樣的一個函數,它會將每一個參數值轉換成它的SQL字面量符號。
|
||||
Exec方法使用SQL字面量替换在查询字符串中的每个'?';SQL字面量表示相应参数的值,它有可能是一个布尔值,一个数字,一个字符串,或者nil空值。用这种方式构造查询可以帮助避免SQL注入攻击;这种攻击就是对手可以通过利用输入内容中不正确的引文来控制查询语句。在Exec函数内部,我们可能会找到像下面这样的一个函数,它会将每一个参数值转换成它的SQL字面量符号。
|
||||
|
||||
```go
|
||||
func sqlQuote(x interface{}) string {
|
||||
@@ -42,9 +42,9 @@ func sqlQuote(x interface{}) string {
|
||||
}
|
||||
```
|
||||
|
||||
switch語句可以簡化if-else鏈,如果這個if-else鏈對一連串值做相等測試。一個相似的type switch(類型開關)可以簡化類型斷言的if-else鏈。
|
||||
switch语句可以简化if-else链,如果这个if-else链对一连串值做相等测试。一个相似的type switch(类型开关)可以简化类型断言的if-else链。
|
||||
|
||||
在它最簡單的形式中,一個類型開關像普通的switch語句一樣,它的運算對象是x.(type)-它使用了關鍵詞字面量type-併且每個case有一到多個類型。一個類型開關基於這個接口值的動態類型使一個多路分支有效。這個nil的case和if x == nil匹配,併且這個default的case和如果其它case都不匹配的情況匹配。一個對sqlQuote的類型開關可能會有這些case:
|
||||
在它最简单的形式中,一个类型开关像普通的switch语句一样,它的运算对象是x.(type)-它使用了关键词字面量type-并且每个case有一到多个类型。一个类型开关基于这个接口值的动态类型使一个多路分支有效。这个nil的case和if x == nil匹配,并且这个default的case和如果其它case都不匹配的情况匹配。一个对sqlQuote的类型开关可能会有这些case:
|
||||
|
||||
```go
|
||||
switch x.(type) {
|
||||
@@ -56,17 +56,17 @@ switch x.(type) {
|
||||
}
|
||||
```
|
||||
|
||||
和(§1.8)中的普通switch語句一樣,每一個case會被順序的進行考慮,併且當一個匹配找到時,這個case中的內容會被執行。當一個或多個case類型是接口時,case的順序就會變得很重要,因爲可能會有兩個case同時匹配的情況。default case相對其它case的位置是無所謂的。它不會允許落空發生。
|
||||
和(§1.8)中的普通switch语句一样,每一个case会被顺序的进行考虑,并且当一个匹配找到时,这个case中的内容会被执行。当一个或多个case类型是接口时,case的顺序就会变得很重要,因为可能会有两个case同时匹配的情况。default case相对其它case的位置是无所谓的。它不会允许落空发生。
|
||||
|
||||
註意到在原來的函數中,對於bool和string情況的邏輯需要通過類型斷言訪問提取的值。因爲這個做法很典型,類型開關語句有一個擴展的形式,它可以將提取的值綁定到一個在每個case范圍內的新變量。
|
||||
注意到在原来的函数中,对于bool和string情况的逻辑需要通过类型断言访问提取的值。因为这个做法很典型,类型开关语句有一个扩展的形式,它可以将提取的值绑定到一个在每个case范围内的新变量。
|
||||
|
||||
```go
|
||||
switch x := x.(type) { /* ... */ }
|
||||
```
|
||||
|
||||
這里我們已經將新的變量也命名爲x;和類型斷言一樣,重用變量名是很常見的。和一個switch語句相似地,一個類型開關隱式的創建了一個語言塊,因此新變量x的定義不會和外面塊中的x變量衝突。每一個case也會隱式的創建一個單獨的語言塊。
|
||||
这里我们已经将新的变量也命名为x;和类型断言一样,重用变量名是很常见的。和一个switch语句相似地,一个类型开关隐式的创建了一个语言块,因此新变量x的定义不会和外面块中的x变量冲突。每一个case也会隐式的创建一个单独的语言块。
|
||||
|
||||
使用類型開關的擴展形式來重寫sqlQuote函數會讓這個函數更加的清晰:
|
||||
使用类型开关的扩展形式来重写sqlQuote函数会让这个函数更加的清晰:
|
||||
|
||||
```go
|
||||
func sqlQuote(x interface{}) string {
|
||||
@@ -88,6 +88,6 @@ func sqlQuote(x interface{}) string {
|
||||
}
|
||||
```
|
||||
|
||||
在這個版本的函數中,在每個單一類型的case內部,變量x和這個case的類型相同。例如,變量x在bool的case中是bool類型和string的case中是string類型。在所有其它的情況中,變量x是switch運算對象的類型(接口);在這個例子中運算對象是一個interface{}。當多個case需要相同的操作時,比如int和uint的情況,類型開關可以很容易的合併這些情況。
|
||||
在这个版本的函数中,在每个单一类型的case内部,变量x和这个case的类型相同。例如,变量x在bool的case中是bool类型和string的case中是string类型。在所有其它的情况中,变量x是switch运算对象的类型(接口);在这个例子中运算对象是一个interface{}。当多个case需要相同的操作时,比如int和uint的情况,类型开关可以很容易的合并这些情况。
|
||||
|
||||
盡管sqlQuote接受一個任意類型的參數,但是這個函數隻會在它的參數匹配類型開關中的一個case時運行到結束;其它情況的它會panic出“unexpected type”消息。雖然x的類型是interface{},但是我們把它認爲是一個int,uint,bool,string,和nil值的discriminated union(可識别聯合)
|
||||
尽管sqlQuote接受一个任意类型的参数,但是这个函数只会在它的参数匹配类型开关中的一个case时运行到结束;其它情况的它会panic出“unexpected type”消息。虽然x的类型是interface{},但是我们把它认为是一个int,uint,bool,string,和nil值的discriminated union(可识别联合)
|
||||
|
Reference in New Issue
Block a user