一个接口类型的变量中可以包含任何类型的值,必须有一种方式来检测它的动态类型,即运行时在变量中存储的值的实际类型。
1.
if v, ok := varI.(T); ok {//TOO}
以上代码中,v返回的接口变量中(类型名和类型的值),而ok返回的是一个bool尔值
可以看下面的例子:
package mainimport "fmt"type Tools interface {Get() int}type A struct {i int}func (a *A)Get() int {return a.i}type B struct {i int}func (b *B)Get() int {return b.i}func main() {var tool Toolsa := &A{10}tool = aif v,ok := tool.(*A) ; ok {fmt.Printf("tool包含%T类型,他的值是:%v\n",v,v)}else {fmt.Printf("tool不包含*A类型\n")}if v,ok := tool.(*B); ok {fmt.Printf("tool包含%T类型,他的值是:%v\n",v,v)}else {fmt.Printf("tool不包含*B类型\n")}}
打印结果:**tool包含*main.A类型,他的值是:&{10}****tool不包含*B类型**
从结果可以得知,这个v,拿到的是存在接口变量中的:结构体+值,而ok只是个bool,负责执行判断语句的条件
使用type-switch
接口变量的类型也可以使用一种特殊形式的switch来检测
switch t := tool.(type) {case *A:fmt.Printf("Type A %T with value %v\n", t, t)case *B:fmt.Printf("Type B %T with value %v\n", t, t)case nil:fmt.Printf("nil value: nothing to check?\n")default:fmt.Printf("Unexpected type %T\n", t)}
输出:Type A *main.A with value &{10}
变量t得到了tool的值和类型,所有case语句中列举的类型(nil除外) 都必须实现对应的接口(在上例中即Shaper),如果被检测类型没有在case语句列举的类型中,就会执行default语句.
如果只是检测接口变量的类型,不使用他的值,那么就可以不需要赋值语句:
switch tool.(type) {case *A:fmt.Println("接口变量包含*A这个类型")case *B:fmt.Println("接口变量包含*B这个类型")default:}
输出:接口变量包含*A这个类型
类型分类函数
类型分类函数,它有一个可变长度参数,可以是任意类型的数组,它会根据数组元素的实际类型执行不同的动作:
func classifier(items ...interface{}) {for i, x := range items {switch x.(type) {case bool:fmt.Printf("Param #%d is a bool\n", i)case float64:fmt.Printf("Param #%d is a float64\n", i)case int, int64:fmt.Printf("Param #%d is a int\n", i)case nil:fmt.Printf("Param #%d is a nil\n", i)case string:fmt.Printf("Param #%d is a string\n", i)default:fmt.Printf("Param #%d is unknown\n", i)}}}
如果一个接口变量里存有多个类型如何检测:
package mainimport ("fmt")type Simpler interface {Get() intSet(int)}/*struct Simple*/type Simple struct {n int}func (s Simple)Get() int {return s.n}func (s Simple)Set(i int) {s.n =i}func ShowValue(s Simpler,i int) {s.Set(i)fmt.Println("Simper get value: ",s.Get())}type RSimple struct {n int}func (s RSimple)Get() int {return s.n}func (s RSimple)Set(i int) {s.n =i}func main() {rsi := &RSimple{10}si := &Simple{200}sim := []Simpler{rsi,si}//将类型变量保存到接口切片里。fi(sim)}//封装一个函数func fi(s []Simpler) {for _,x := range s { //i为索引,x为变量类型switch x.(type) {case *RSimple:fmt.Printf("接口变量包含%T,值为:%v\n",x,x)case *Simple:fmt.Printf("接口变量包含%T,值为:%v\n",x,x)default:fmt.Println("unknown!!!")}}}
输出:接口变量包含*main.RSimple,值为:&{10}接口变量包含*main.Simple,值为:&{200}
测试一个值是否实现了某个接口
type Stringer interface {String()string}type S struct {name string}func (s *S)String() string { return s.name}func main() {s := new(S)s.name = "Jack"var v Stringerv = s//结构体s是否实现了Stringer接口if sv,ok := v.(Stringer);ok {fmt.Printf("%T 实现了String(): %s\n",sv,sv)}}
输出:*main.S 实现了String(): Jack
