一个接口类型的变量中可以包含任何类型的值,必须有一种方式来检测它的动态类型,即运行时在变量中存储的值的实际类型。
1.
if v, ok := varI.(T); ok {
//TOO
}
以上代码中,v
返回的接口变量中(类型名和类型的值),而ok
返回的是一个bool
尔值
可以看下面的例子:
package main
import "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 Tools
a := &A{10}
tool = a
if 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 main
import (
"fmt"
)
type Simpler interface {
Get() int
Set(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 Stringer
v = s
//结构体s是否实现了Stringer接口
if sv,ok := v.(Stringer);ok {
fmt.Printf("%T 实现了String(): %s\n",sv,sv)
}
}
输出:*main.S 实现了String(): Jack