定义
类型断言是判断接口的数据类型,语法如下
x.(T)
x:表示类型为interface{}的变量
T:表示断言可能的数据类型
类型断言有两个返回值,第一个返回值是空接口的数值和数据类型;第二个返回值是布尔型,判断x是不是T的数据类型。
具体实现
类型断言有那么一点像C++的函数模板,就像我们对接口参数化,等到运行时根据实际情况再对它赋值。通过类型断言我们得到接口的数据类型后,再对其进行相关操作。我们直接来看例子,完整代码如下
package main
import "fmt"
type sinner struct {
name string
loc string
rating float64
id int
}
type initialize interface {
init(sinner) sinner
}
func getData(s interface{}) {
if data, flag := s.(sinner); flag {
fmt.Printf("name is %v\n", data.name)
} else if data, flag := s.(float64); flag {
fmt.Printf("float64 is %v\n", data)
} else if data, flag := s.(string); flag {
fmt.Printf("string is %v\n", data)
}
}
func (*sinner) init(s sinner) sinner {
s = sinner{name: "Ishmael", loc: "Limbus Company", rating: 9.9, id: 1}
return s
}
func startInit(i initialize, s sinner) {
tmp := i.init(s)
getData(tmp)
getData(tmp.rating)
getData(tmp.loc)
}
func main() {
var ishmael sinner
startInit(&ishmael, ishmael)
}
我们定义了一个结构体sinner和一个接口initialize,并通过结构体去绑定接口来实现接口的里的init方法,这一块知识主要是这篇文章的知识Go语言--接口的定义与使用。
通过接口我们为结构体内不同类型的变量赋初始值。我们删去这些代码,只保留类型断言的部分再看看。
type sinner struct {
name string //"Ishmael"
loc string //"Limbus Company"
rating float64 //9.9
id int //1
}
func getData(s interface{}) {
if data, flag := s.(sinner); flag {
fmt.Printf("name is %v\n", data.name)
} else if data, flag := s.(float64); flag {
fmt.Printf("float64 is %v\n", data)
} else if data, flag := s.(string); flag {
fmt.Printf("string is %v\n", data)
}
}
func (*sinner) init(s sinner) sinner {
s = sinner{name: "Ishmael", loc: "Limbus Company", rating: 9.9, id: 1}
return s
}
func startInit(i initialize, s sinner) {
tmp := i.init(s) //type:sinner
getData(tmp)
getData(tmp.rating)
getData(tmp.loc)
}
可以看到,我们定义的getData()方法,传入的参数类型为interface。但在startInit()方法中,我们调用getData()时传入的是三种不同类型的参数:结构体类型,flaot64双精度浮点数类型,string类型。就是没有interface类型。
尽管如此,程序还是能正常运行,结果如下
name is Ishmael
float64 is 9.9
string is Limbus Company
这是由于:空接口是接口类型的特殊形式,空接口没有设置任何方法,任何变量都可以使用空接口。空接口可以保存任意数据,也可以从空接口中取出数据。
所以我们传入的结构体类型,flaot64双精度浮点数类型,string类型,都被interface保存了下列。(不能说被转换为了interface类型,接口只是保存了我们存进去的数据类型,我们取出来的不是接口而是那个数据)
在if判断语句中,可以看到当s的类型为sinner结构体类型/float64/string类型时,才会执行对应的语句。
if data, flag := s.(sinner); flag {
fmt.Printf("name is %v\n", data.name)
}