2.07 Go之接口和类型之间的转换

2.07 Go之接口和类型之间的转换

什么是接口和类型之间的转换?

Go语言中使用接口断言(type assertions)将接口转换成另外一个接口,也可以将接口转换为另外的类型。

类型断言的格式

格式:

i.(T)i表示一个接口的类型和T表示一个类型

断言的基本格式:

t := i.(T)
/*
i 代表接口变量,T 代表转换的目标类型,t 代表转换后的变量
*/

三种情况:

  • 断言的类型T是一个具体类型,类型断言检查i的动态类型是否和T相同。如果检查成功,类型断言结果是i的动态值,类型是T。如果检查失败则会抛出panic

var w io.Writer
w = os.Stdout
f := w.(*os.File) // 成功: f == os.Stdout
c := w.(*bytes.Buffer) // 死机:接口保存*os.file,而不是*bytes.buffer
  • 断言的类型T是一个接口类型,类型断言检查是否i的动态类型满足T,如果这个检查成功了,动态值没有获取到;这个结果仍然是一个有相同类型和值部分的接口值,但是结果有类型T

var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) // 成功:*os.file具有读写功能
w = new(ByteCounter)
rw = w.(io.ReadWriter) // 死机:*字节计数器没有读取方法
/*
第一个类型断言后,w 和 rw 都持有 os.Stdout 因此它们每个有一个动态类型 *os.File,但是变量 w 是一个 io.Writer 类型只对外公开出文件的 Write 方法,然而 rw 变量也只公开它的 Read 方法。
*/
  • 断言对象是一个nil接口值,不论断言类似是什么这个类型断言都会失败

如果i没有完全实现T接口的方法,这个语句将会触发宕机。可以写成这样:

t,ok := i.(T)
/*
如果发生接口未实现时,将会把 ok 置为 false,t 置为 T 类型的 0 值。
正常实现时,ok 为 true。这里 ok 可以被认为是:i 接口是否实现 T 类型的结果。
*/

将接口转换为其他接口

概念:

一个类型同时实现了两个接口,可以在这两个接口之间切换

示例代码:

package main

import "fmt"

/* 定义飞行动物接口 */
type Flyer interface {
   Fly()
}

/* 定义行走动物接口 */
type Walker interface {
   Walk()
}

/* 定义鸟类型 */
type bird struct {
}

/* 定义鸟类型的方法 */
func (b *bird) Fly() {
   fmt.Println("bird behavior : fly")
}

func (b *bird) Walk() {
   fmt.Println("bird behavior : walk")
}

/* 定义🐖类型 */
type pig struct {
}

/* 定义🐖类型的方法 */
func (p *pig) Walk() {
   fmt.Println("pig behavior : walk")
}

// 调用上述方法,使用类型断言
func main() {
   // 创建动物的名字到实例的映射
   animals := map[string]interface{}{
       "bird" : new(bird),
       "pig" : new(pig),
  }

   // 遍历map
   for name, obj := range animals {
       // 使用类型断言判断值得类型
       f, isFlyer := obj.(Flyer)
       w, isWalker := obj.(Walker)

       // 打印结果
       fmt.Printf("name: %s isFlyer: %v isWalker: %v\n", name, isFlyer, isWalker)

       // 判断结果
       if isFlyer {
           f.Fly()
      }

       if isWalker {
           w.Walk()
      }
  }
}
/*
最终结果bird调用了Fly()和Walk()方法,因为bird类型实现了两个方法
*/

将接口转换为其他类型

代码示例:

// 由于 pig 实现了 Walker 接口,因此可以被隐式转换为 Walker 接口类型保存于 a 中
p1 := new(pig)
var a Walker = p1
// 由于 a 中保存的本来就是 *pig 本体,因此可以转换为 *pig 类型
p2 := a.(*pig)
// p1 和 p2 指针是相同的
fmt.Printf("p1=%p p2=%p", p1, p2)

注意:

如果将*pig转换为*bird类型将会报错。

panic: interface conversion: main.Walker is *main.pig, not *main.bird
/*
接口转换时,main.Walker 接口的内部保存的是 *main.pig,而不是 *main.bird。

因此,接口在转换为其他类型时,接口内保存的实例对应的类型指针,必须是要转换的对应的类型指针。
*/

 

posted @   俊king  阅读(219)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示