Golang中的类型和类型断言

LeeYubo · · 9539 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

#### golang中的类型 golang中的有两种类型,**静态类型(static type)**和**动态类型(dynamic type)** **静态类型**:静态类型是在声明变量的时候指定的类型,一个变量的静态类型是永恒不变的,所以才被称为静态类型,也可以简称为类型,普通变量只有静态类型。 ``` package main import "fmt" func main() { // 变量i和变量g只有静态类型,变量i的类型为int,i的类型为main.Goose, var i int var g Goose fmt.Printf("%T\n", i) fmt.Printf("%T\n", g) } type Goose struct { age int name string } 执行结果: int main.Sparrow ``` **动态类型**:接口类型变量除了静态类型之外还有动态类型,动态类型是由给接口类型变量赋值的具体值的类型来决定的,除了动态类型之外还有动态值,动态类型和动态值是对应的,动态值就是接口类型变量赋值的具体值,之所以被称为动态类型,是因为接口类型的动态类型是会变化的,由被赋予的值来决定。 ``` package main import "fmt" func main() { // 动态类型 var b Bird // b 是main.Sparrow类型 b = Sparrow{} fmt.Printf("%T\n", b) // b 是main.Parrot类型 b = Parrot{} fmt.Printf("%T\n", b) } type Bird interface { fly() sing() } // Goose implement Bird interface type Sparrow struct { age int name string } func (s Sparrow) fly() { fmt.Println("I am flying.") } func (s Sparrow) sing() { fmt.Println("I can sing.") } type Parrot struct { age int kind int name string } func (p Parrot) fly() { fmt.Println("I am flying.") } func (p Parrot) sing() { fmt.Println("I can sing.") } 执行结果: main.Sparrow main.Parrot ``` 但是我们在变量*b*赋值之前直接获取它的类型会发现返回的结果是*nil*,这看起来很奇怪,*interface*在Golang里也是一种类型,那它声明的变量的类型为什么是*nil*呢? ``` package main import "fmt" func main() { // 动态类型 var b Bird fmt.Printf("interface类型变量的类型:%T\n", b) } type Bird interface { fly() sing() } 执行结果: interface类型变量的类型:<nil> ``` 首先我们需要明确,一个接口类型变量在没有被赋值之前,它的动态类型和动态值都是 *nil* 。在使用 *fmt.Printf("%T\n")* 获取一个变量的类型时,其实是调用了reflect包的方法进行获取的, *reflect.TypeOf* 获取的是接口变量的动态类型, *reflect.valueOf()* 获取的是接口变量的动态值。所以 *fmt.Printf("%T\n",b)* 展示的是 *reflect.TypeOf* 的结果,由于接口变量 *b* 还没有被赋值,所以它的动态类型是 *nil* ,动态值也会是 *nil* 。 对比来看,为什么只是经过了声明未赋值的变量的类型不是 *nil* 呢?就像在静态类型部分中所展示的那样。原因如下: 我们先来看一下 *reflect.TypeOf* 函数的定义,*func TypeOf(i interface{}) Type{}* ,函数的参数是一个 *interface* 类型的变量,在调用 *TypeOf* 时,在接口变量 *b* 没有赋值之前,它的静态类型与参数类型一致,不需要做转换,因为 *b* 的动态类型为 *nil*,所以 *TypeOf* 返回的结果为 *nil* 。那为什么变量 *i* 和变量 *g* 的类型不为 *nil* 呢?当变量 *i* 调用 *TypeOf* 时,会进行类型的转换,将int型变量i转换为 *interface* 型,在这个过程中会将变量 *i* 的类型作为 *b* 的动态类型,变量 *i* 的值(在这里是变量 *i* 的零值0)作为 *b* 的动态值。因为 *TypeOf()* 获取的是变量 *b* 的动态类型,所以这个时候展示出的类型为 *int*。 #### golang中的类型断言 因为接口变量的动态类型是变化的,有时我们需要知道一个接口变量的动态类型究竟是什么,这就需要使用类型断言,断言就是对接口变量的类型进行检查,其语法结构如下: ``` value, ok := x.(T) x表示要断言的接口变量; T表示要断言的目标类型; value表示断言成功之后目标类型变量; ok表示断言的结果,是一个bool型变量,true表示断言成功,false表示失败,如果失败value的值为nil。 ``` 代码示例如下: ``` package main import ( "fmt" ) func main() { // 动态类型 var b Bird // b 是main.Sparrow类型 b = Sparrow{} Listen(b) // b 是main.Parrot类型 b = Parrot{} Listen(b) } func Listen(b Bird) { if _, ok := b.(Sparrow); ok { fmt.Println("Listren sparrow sing.") } if _, ok := b.(Parrot); ok { fmt.Println("Listren parrot sing.") } b.sing() } type Bird interface { fly() sing() } type Sparrow struct { age int name string } func (s Sparrow) fly() { fmt.Println("I am sparrow, i can fly.") } func (s Sparrow) sing() { fmt.Println("I am sparrow, i can sing.") } type Parrot struct { age int kind int name string } func (p Parrot) fly() { fmt.Println("I am parrot, i can fly.") } func (p Parrot) sing() { fmt.Println("I am parrot, i can sing.") } 执行结果如下: Listren sparrow sing. I am sparrow, i can sing. Listren parrot sing. I am parrot, i can sing. ``` 有时结合 *switch* 使用更方便 ``` func Listen(b Bird) { switch b.(type) { case Sparrow: fmt.Println("Listren sparrow sing.") case Parrot: fmt.Println("Listren parrot sing.") default: fmt.Println("Who are you? I don't know you.") } b.sing() } ``` 参考: https://studygolang.com/articles/9331 https://studygolang.com/articles/11374 《go语言圣经》

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

9539 次点击  
加入收藏 微博
1 回复  |  直到 2023-02-25 09:51:31
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传