Go语言圣经 - 第7章 接口 - 7.13 类型分支

第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(可识别联合)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值