第7章 接口
接口类型是对其它类型行为的抽象和概括.接口类型不会和特定的实现细节绑定在一起,这种抽象的方式能让我们的函数更加的灵活和更具有适应能力
Go语言的接口比较特殊,因为它是满足隐式实现的。也就是说,我们无需给具体类型定义所有满足足的接口类型,只需要让类型拥有一些简单必要的方法。这样我们新建一个接口类型,满足具体类型,并且我们不需要更改这些类型的定义。当我们使用的类型来自于不受我们控制的包时,这种机制比较有用
7.13 类型分支
接口被以两种方式使用,第一个方式中,以io.Reader/Writer,fmt.Stringer,sort.Interface,http.Handler和error为典型,一个接口的方法表达了实现了这个接口的具体类型间的相似性,但是隐藏了代码的细节和这些具体类型本身的操作,重点在于方法上而不是类型上
第二个方式是利用接口值可以持有各种具体值的能力,将这个接口认为是这些类型的联合。类型断言用来动态的区别这些类型。这种情况中,重点在于满足这个接口,而不在于接口的方法,它也没有任何信息的隐藏,我们将这种方式使用接口描述为discriminated unions(可变识联合)
我们看一个Go语言查询SQL数据库的API例子
func listTracks(db sql.DB, artist string, minYear, maxYear int) {
result, err := db.Exec (
"SELECT * FROM tracks WHERE artist = ? AND ? <= year AND year <= ?",
artist,minYear,maxYear)
// ...
}
Exec方法方法使用SQL字面量替换在查询字符串中的每个’ ?‘,SQL字面量表示相应的参数的值,它有可能是一个bool值,一个数字,一个字符串或者nil空值,它可以防止攻击者使用不正确的引号来控制查询语句,在Exec内部,我们可能会看到一个如下将参数值转换成它的SQL字面量符号
func sqlQuote(x interface{})string {
if x == nil {
return "NULL"
}else if _,ok := x.(int); ok {
return fmt.Sprintf("%d",x)
}else if _, ok := x.(uint);ok {
return fmt.Sprintf("%d",x)
}else if b,ok := x.(bool); ok {
if b {
return "TRUE"
}
return "FALSE"
}else if s, ok := x.(string);ok {
return sqlQuoteString(s) // (not shown)
}else {
panic(fmt.Sprintf("unexpected type %T: %v",x,x))
}
}
但是上述的结构使用可太多if else语句,有点冗杂,实际上我们可以使用switch结构
switch x.(type) {
case nil: //...
case int,uint: //...
case bool: //...
case string: //...
default //...
}
在原来的函数中我们使用了类型断言,但是类型分支语句中我们使用扩展形式就行了,它可以将提取的值绑定到一个在每个case范围内都有效的变量
switch := x.(type) {/*..*/}
我们这里将新变量也命名为了x,和类型断言一样,重用变量名很常见,和一个stitch语句相似的,类型分支会隐式的创建语法块,因此内部
x不会和外部x冲突
使用类型分支的扩展形式来重写sqlQuote函数会更加清晰
func sqlQuote(x interface{}) string {
switch x := x.(type) {
case nil:
return "NULL"
case int, uint:
return fmt.Sprintf("%d", x)
case bool:
if x {
return "TRUE"
}
return "FALSE"
case string:
return sqlQuoteString(x) // (not shown)
default:
panic(fmt.Sprintf("unexpected type %T: %v",x,x))
}
}
在这里,每一个单一类型的case内部,变量x和这个case的类型相同,例如x在bool的case中是bool类型,在string的case中是string类型,在其他情况中,变量x时switch运算对象的类型(接口),在这个例子中运算对象是一个interface{},但是我们把它认为是一个int,uint,bool,string,和nil值的discriminated union(可识别联合)