前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go 语言入门与进阶:反射基础

Go 语言入门与进阶:反射基础

作者头像
aoho求索
发布2021-10-14 16:49:07
4510
发布2021-10-14 16:49:07
举报
文章被收录于专栏:aoho求索aoho求索

前文回顾

如果你还没有 Go 语言基础,建议阅读我的 从零学 Go专栏。

前面的文章主要介绍了 Go 包依赖管理 GOPATH 和 Go Module 的应用实践。本文将会介绍 Go 反射相关的内容。

反射基础

反射是一项功能强大的工具,它给开发人员提供了在运行时对代码本身进行访问和修改的能力。接下来我们介绍 Go 反射中 Type 和 Value 两个重要的概念。

我们首先定义一些简单的结构体和方法,用于我们后面的实验验证,代码如下所示,主要位于 feature/relection/reflection.go 文件下:

代码语言:javascript
复制
package main

import "fmt"

// 定义一个人的接口
type Person interface {

 // 和人说hello
 SayHello(name string)
 // 跑步
 Run() string
}

type Hero struct {
 Name string
 Age int
 Speed int
}

func (hero *Hero) SayHello(name string)  {
 fmt.Println("Hello " + name, ", I am " + hero.Name)
}

func (hero *Hero) Run() string{
 fmt.Println("I am running at speed " + string(hero.Speed))
 return "Running"
}

上述代码中我们定义了一个 Person 接口,以及定义了 Hero 结构体来实现 Person 接口中的方法,同时 Hero 结构体中还包含 3 个成员字段。

Go 的反射与 Java 等语言有不小的区别,主要通过 Type 和 Value 两个基本概念来阐述。其中 Type 主要用于表示被反射变量的类型信息,而 Value 用于表示被反射变量自身的实例信息。Go 的反射实现主要位于 reflect 包中。

reflect.Type 类型对象

通过 reflect#TypeOf 方法,我们可以轻松地获取一个变量的类型信息 reflect.Type。通过 reflect.Type 类型对象,我们访问到其对应类型的各项类型信息。我们可以创建一个 Hero 结构体,通过 reflect#TypeOf 来查看其对应的类型信息,代码如下所示:

代码语言:javascript
复制
func main()  {
 // 获取实例的反射类型对象
 typeOfHero := reflect.TypeOf(Hero{})
 fmt.Printf("Hero's type is %s, kind is %s", typeOfHero, typeOfHero.Kind())

}

运行结果如下所示:

代码语言:javascript
复制
Hero's type is main.Hero, kind is struct

在 Go 中,存在着 Type (类型)和 Kind (种类) 区别,如上面结果所展示,Hero 的类型是 main.Hero,种类是 struct。Type 是指变量所属的类型,包括系统的原生数据类型如 int、string等和我们通过 type 关键字定义的类型,比如我们定义的 Hero 结构体,这些类型的名称一般就是其类型本身。而 Kind 是指变量类型的所归属的品种,参考 reflect.Kind 中的定义,主要有以下类型:

代码语言:javascript
复制
type Kind uint

const (
 Invalid Kind = iota
 Bool
 Int
 Int8
 Int16
 Int32
 Int64
 Uint
 Uint8
 Uint16
 Uint32
 Uint64
 Uintptr
 Float32
 Float64
 Complex64
 Complex128
 Array
 Chan
 Func
 Interface
 Map
 Ptr
 Slice
 String
 Struct
 UnsafePointer
)

一般我们通过 type 关键字定义的结构体都属于 Struct,而指针变量的种类统一为 Ptr,比如下面代码:

代码语言:javascript
复制
 fmt.Printf("*Hero's type is %s, kind is %s",reflect.TypeOf(&Hero{}), reflect.TypeOf(&Hero{}).Kind())

上述代码中通过 reflect#TypeOf 获取了 Hero 指针的类型对象,它的输出将会是:

代码语言:javascript
复制
*Hero's type is *main.Hero, kind is ptr

这说明 &Hero{} 的类型是 *main.Helo,归属于种类 ptr。对于指针类型的变量,可以使用 Type#Elem 获取到指针指向变量的真实类型对象,如下例子所示:

代码语言:javascript
复制
 typeOfPtrHero := reflect.TypeOf(&Hero{})
 fmt.Printf("*Hero's type is %s, kind is %s\n",typeOfPtrHero, typeOfPtrHero.Kind())
 typeOfHero = typeOfPtrHero.Elem()
 fmt.Printf(" typeOfPtrHero elem to typeOfHero, Hero's type is %s, kind is %s", typeOfHero, typeOfHero.Kind())

预期输出为:

代码语言:javascript
复制
*Hero's type is *main.Hero, kind is ptr
 typeOfPtrHero elem to typeOfHero, Hero's type is main.Hero, kind is struct

通过 typeOfPtrHero#Elem,我们可以获取到 *main.Helo 指针原类型 main.Hero 的类型对象。

小结

本文主要介绍了 Go 语言的反射基础。通过反射,我们可以拿到丰富的类型信息,比如变量的字段名称、类型信息和结构体信息等,并通过这些类型信息做一些灵活的工作。Go 的反射实现了反射的大多数功能,获取类型信息需要配合使用标准库中的词法、语法解析器和抽象语法树对源码进行扫描。

下一篇文章将会继续介绍 Go 语言的反射 reflect 相关内容。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-10-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 aoho求索 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前文回顾
  • 如果你还没有 Go 语言基础,建议阅读我的 从零学 Go专栏。
  • 反射基础
    • reflect.Type 类型对象
    • 小结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档