一个接口类型的变量中可以包含任何类型的值,必须有一种方式来检测它的动态类型,即运行时在变量中存储的值的实际类型。

1.

  1. if v, ok := varI.(T); ok {
  2. //TOO
  3. }

以上代码中,v返回的接口变量中(类型名和类型的值),而ok返回的是一个bool尔值
可以看下面的例子:

  1. package main
  2. import "fmt"
  3. type Tools interface {
  4. Get() int
  5. }
  6. type A struct {
  7. i int
  8. }
  9. func (a *A)Get() int {
  10. return a.i
  11. }
  12. type B struct {
  13. i int
  14. }
  15. func (b *B)Get() int {
  16. return b.i
  17. }
  18. func main() {
  19. var tool Tools
  20. a := &A{10}
  21. tool = a
  22. if v,ok := tool.(*A) ; ok {
  23. fmt.Printf("tool包含%T类型,他的值是:%v\n",v,v)
  24. }else {
  25. fmt.Printf("tool不包含*A类型\n")
  26. }
  27. if v,ok := tool.(*B); ok {
  28. fmt.Printf("tool包含%T类型,他的值是:%v\n",v,v)
  29. }else {
  30. fmt.Printf("tool不包含*B类型\n")
  31. }
  32. }

打印结果:
**tool包含*main.A类型,他的值是:&{10}**
**tool不包含*B类型**
从结果可以得知,这个v,拿到的是存在接口变量中的:结构体+值,而ok只是个bool,负责执行判断语句的条件

使用type-switch

接口变量的类型也可以使用一种特殊形式的switch来检测

  1. switch t := tool.(type) {
  2. case *A:
  3. fmt.Printf("Type A %T with value %v\n", t, t)
  4. case *B:
  5. fmt.Printf("Type B %T with value %v\n", t, t)
  6. case nil:
  7. fmt.Printf("nil value: nothing to check?\n")
  8. default:
  9. fmt.Printf("Unexpected type %T\n", t)
  10. }

输出:
Type A *main.A with value &{10}

变量t得到了tool的值和类型,所有case语句中列举的类型(nil除外) 都必须实现对应的接口(在上例中即Shaper),如果被检测类型没有在case语句列举的类型中,就会执行default语句.

如果只是检测接口变量的类型,不使用他的值,那么就可以不需要赋值语句:

  1. switch tool.(type) {
  2. case *A:
  3. fmt.Println("接口变量包含*A这个类型")
  4. case *B:
  5. fmt.Println("接口变量包含*B这个类型")
  6. default:
  7. }

输出:
接口变量包含*A这个类型

类型分类函数

类型分类函数,它有一个可变长度参数,可以是任意类型的数组,它会根据数组元素的实际类型执行不同的动作:

  1. func classifier(items ...interface{}) {
  2. for i, x := range items {
  3. switch x.(type) {
  4. case bool:
  5. fmt.Printf("Param #%d is a bool\n", i)
  6. case float64:
  7. fmt.Printf("Param #%d is a float64\n", i)
  8. case int, int64:
  9. fmt.Printf("Param #%d is a int\n", i)
  10. case nil:
  11. fmt.Printf("Param #%d is a nil\n", i)
  12. case string:
  13. fmt.Printf("Param #%d is a string\n", i)
  14. default:
  15. fmt.Printf("Param #%d is unknown\n", i)
  16. }
  17. }
  18. }

如果一个接口变量里存有多个类型如何检测:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type Simpler interface {
  6. Get() int
  7. Set(int)
  8. }
  9. /*struct Simple*/
  10. type Simple struct {
  11. n int
  12. }
  13. func (s Simple)Get() int {
  14. return s.n
  15. }
  16. func (s Simple)Set(i int) {
  17. s.n =i
  18. }
  19. func ShowValue(s Simpler,i int) {
  20. s.Set(i)
  21. fmt.Println("Simper get value: ",s.Get())
  22. }
  23. type RSimple struct {
  24. n int
  25. }
  26. func (s RSimple)Get() int {
  27. return s.n
  28. }
  29. func (s RSimple)Set(i int) {
  30. s.n =i
  31. }
  32. func main() {
  33. rsi := &RSimple{10}
  34. si := &Simple{200}
  35. sim := []Simpler{rsi,si}//将类型变量保存到接口切片里。
  36. fi(sim)
  37. }
  38. //封装一个函数
  39. func fi(s []Simpler) {
  40. for _,x := range s { //i为索引,x为变量类型
  41. switch x.(type) {
  42. case *RSimple:
  43. fmt.Printf("接口变量包含%T,值为:%v\n",x,x)
  44. case *Simple:
  45. fmt.Printf("接口变量包含%T,值为:%v\n",x,x)
  46. default:
  47. fmt.Println("unknown!!!")
  48. }
  49. }
  50. }

输出:
接口变量包含*main.RSimple,值为:&{10}
接口变量包含*main.Simple,值为:&{200}

测试一个值是否实现了某个接口

  1. type Stringer interface {
  2. String()string
  3. }
  4. type S struct {
  5. name string
  6. }
  7. func (s *S)String() string { return s.name}
  8. func main() {
  9. s := new(S)
  10. s.name = "Jack"
  11. var v Stringer
  12. v = s
  13. //结构体s是否实现了Stringer接口
  14. if sv,ok := v.(Stringer);ok {
  15. fmt.Printf("%T 实现了String(): %s\n",sv,sv)
  16. }
  17. }

输出:
*main.S 实现了String(): Jack