go语言特性--反射 青训营

简介: go语言特性--反射 青训营

go语言特性--反射

这篇博客简单总结一下go语言的一个原理--反射。

反射是指在程序运行期间对程序本身进行访问和修改的能力。程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分。在运行程序时,程序无法获取自身的信息。

但是支持反射的语言可以在程序编译期间将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期间获取类型的反射信息,并且有能力修改它们。

1. reflect

任何接口值都是由==类型==和==值==组成的。

反射中类型还区分**类型(type)种类(kind)**两种。

type cat struct{
  // ...
}
// cat 就是类型,而struct是种类
// 种类:struct, 指针, bool, int...

go的反射功能包---reflect

获取类型和具体的值:

// TypeOf()
func f(x interface{}){
  // 获取空接口的具体类型
  v := reflect.TypeOf(x)
  fmt.Printf("%v\n", v)
  // 获取类型和种类
  fmt.Printf("%v, %v\n", v.Name(), v.Kind())
}
////////////////////////////////////////////////////////////////
// ValueOf()
func f(x interface{}){
  // 获取空接口的具体值
  v := reflect.ValueOf(x)
  fmt.Printf("%v\n", v)
  // 获取值得类型和种类
  fmt.Printf("%v\n", v.Kind())
}

通过反射设置值:

func f(x interface{}){
  // 获取空接口的具体值
  v := reflect.ValueOf(x)
  // 取出v的值并修改
  if v.Elem().Kind() == reflect.Int64{
    v.Elem().SetInt(100)
  }
}
func main(){
  var a int64
  a = 10
  // 要传地址
  f(&a)
}

2. 结构体反射

type student struct {
  Name  string `json:"name"`
  Score int    `json:"score"`
}
func main() {
  stu1 := student{
    Name:  "小王子",
    Score: 90,
  }
  t := reflect.TypeOf(stu1)
  fmt.Println(t.Name(), t.Kind()) // student struct
  // 通过for循环遍历结构体的所有字段信息
  for i := 0; i < t.NumField(); i++ {
    field := t.Field(i) 
    fmt.Printf("name:%s index:%d type:%v json tag:%v\n", field.Name, field.Index, field.Type, field.Tag.Get("json"))
  }
  // 通过字段名获取指定结构体字段信息
  if scoreField, ok := t.FieldByName("Score"); ok {
    fmt.Printf("name:%s index:%d type:%v json tag:%v\n", scoreField.Name, scoreField.Index, scoreField.Type, scoreField.Tag.Get("json"))
  }
}

反射可以使得代码更灵活,但是反射也有缺点:

  1. 代码难以理解。
  2. 反射的代码性能很低。

3. 反射应用

获取interface{}空接口类型参数 的具体类型和值。

.ini 配置文件解析器 (所有的配置文件解析都会用到反射)。

json的序列化和反序列化。

4. reflect包的其他用处

// 比较无法直接用 == 比较的类型,如切片
reflect.DeepEqual(a,b)

反射是在C语言中没有的特性,也比较难理解,最好的方法就是在项目实战中去体会理解反射的用处。

相关文章
|
18小时前
|
存储 编译器 Go
|
2天前
|
安全 Java Go
探索Go语言在高并发环境中的优势
在当今的技术环境中,高并发处理能力成为评估编程语言性能的关键因素之一。Go语言(Golang),作为Google开发的一种编程语言,以其独特的并发处理模型和高效的性能赢得了广泛关注。本文将深入探讨Go语言在高并发环境中的优势,尤其是其goroutine和channel机制如何简化并发编程,提升系统的响应速度和稳定性。通过具体的案例分析和性能对比,本文揭示了Go语言在实际应用中的高效性,并为开发者在选择合适技术栈时提供参考。
|
6天前
|
JSON 人工智能 Go
go 反射的常见用法
go 反射的常见用法
16 4
|
6天前
|
运维 Kubernetes Go
"解锁K8s二开新姿势!client-go:你不可不知的Go语言神器,让Kubernetes集群管理如虎添翼,秒变运维大神!"
【8月更文挑战第14天】随着云原生技术的发展,Kubernetes (K8s) 成为容器编排的首选。client-go作为K8s的官方Go语言客户端库,通过封装RESTful API,使开发者能便捷地管理集群资源,如Pods和服务。本文介绍client-go基本概念、使用方法及自定义操作。涵盖ClientSet、DynamicClient等客户端实现,以及lister、informer等组件,通过示例展示如何列出集群中的所有Pods。client-go的强大功能助力高效开发和运维。
28 1
|
6天前
|
算法 NoSQL 中间件
go语言后端开发学习(六) ——基于雪花算法生成用户ID
本文介绍了分布式ID生成中的Snowflake(雪花)算法。为解决用户ID安全性与唯一性问题,Snowflake算法生成的ID具备全局唯一性、递增性、高可用性和高性能性等特点。64位ID由符号位(固定为0)、41位时间戳、10位标识位(含数据中心与机器ID)及12位序列号组成。面对ID重复风险,可通过预分配、动态或统一分配标识位解决。Go语言实现示例展示了如何使用第三方包`sonyflake`生成ID,确保不同节点产生的ID始终唯一。
go语言后端开发学习(六) ——基于雪花算法生成用户ID
|
20小时前
|
算法 安全 Go
|
2天前
|
监控 NoSQL Go
Go语言中高效使用Redis的Pipeline
Redis 是构建高性能应用时常用的内存数据库,通过其 Pipeline 和 Watch 机制可批量执行命令并确保数据安全性。Pipeline 类似于超市购物一次性结账,减少网络交互时间,提升效率。Go 语言示例展示了如何使用 Pipeline 和 Pipelined 方法简化代码,并通过 TxPipeline 保证操作原子性。Watch 机制则通过监控键变化实现乐观锁,防止并发问题导致的数据不一致。这些机制简化了开发流程,提高了应用程序的性能和可靠性。
7 0
|
4天前
|
NoSQL Go Redis
Go语言中如何扫描Redis中大量的key
在Redis中,遍历大量键时直接使用`KEYS`命令会导致性能瓶颈,因为它会一次性返回所有匹配的键,可能阻塞Redis并影响服务稳定性。为解决此问题,Redis提供了`SCAN`命令来分批迭代键,避免一次性加载过多数据。本文通过两个Go语言示例演示如何使用`SCAN`命令:第一个示例展示了基本的手动迭代方式;第二个示例则利用`Iterator`简化迭代过程。这两种方法均有效地避免了`KEYS`命令的性能问题,并提高了遍历Redis键的效率。
16 0
|
5天前
|
监控 Serverless Go
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
|
6天前
|
关系型数据库 MySQL 数据库连接
Go语言中使用sqlx来操作事务
在应用中,数据库事务保证操作的ACID特性至关重要。`github.com/jmoiron/sqlx`简化了数据库操作。首先安装SQLX和MySQL驱动:`go get github.com/jmoiron/sqlx`和`go get github.com/go-sql-driver/mysql`。导入所需的包后,创建数据库连接并使用`Beginx()`方法开始事务。通过`tx.Commit()`提交或`tx.Rollback()`回滚事务以确保数据一致性和完整性。
8 0