go float64 转int_Go语言的学习笔记(第十三章) 反射

本文介绍了Go语言中的反射机制,详细阐述了反射的定义、用途,以及如何通过`reflect`包实现float64到int的转换。文章通过实例讲解了`TypeOf`和`ValueOf`的用法,讨论了反射的优缺点,并给出了反射在json序列化中的应用。此外,还探讨了反射在实现ini解析器等场景中的作用。
摘要由CSDN通过智能技术生成

不点蓝字,我们哪来故事?

4c9b9d39329d2c8f725914ab635a5ef2.png

Go语言基础之反射

什么是反射

直接看维基百科上的定义:

在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

那我就要问个问题了:不用反射就不能在运行时访问、检测和修改它本身的状态和行为吗?

问题的回答,其实要首先理解什么叫访问、检测和修改它本身状态或行为,它的本质是什么?

实际上,它的本质是程序在运行期探知对象的类型信息和内存结构,不用反射能行吗?可以的!使用汇编语言,直接和内层打交道,什么信息不能获取?但是,当编程迁移到高级语言上来之后,就不行了!就只能通过反射来达到此项技能。

不同语言的反射模型不尽相同,有些语言还不支持反射。《Go语言圣经》中是这样定义反射的:

Go 语言提供了一种机制在 运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称 为反射机制。

为什么要用反射

需要反射的 2 个常见场景:

  1. 有时你需要编写一个函数,但是并不知道传给你的参数类型是什么,可能是没约定好;也可能是传入的类型很多,这些类型并不能统一表示。这时反射就会用的上了。

  2. 有时候需要根据某些条件决定调用哪个函数,比如根据用户的输入来决定。这时就需要对函数和函数的参数进行反射,在运行期间动态地执行函数。

在讲反射的原理以及如何用之前,还是说几点不使用反射的理由:

  • 与反射相关的代码,经常是难以阅读的。在软件工程中,代码可读性也是一个非常重要的指标。

  • Go 语言作为一门静态语言,编码过程中,编译器能提前发现一些类型错误,但是对于反射代码是无能为力的。所以包含反射相关的代码,很可能会运行很久,才会出错,这时候经常是直接 panic,可能会造成严重的后果。

  • 反射对性能影响还是比较大的,比正常代码运行速度慢一到两个数量级。所以,对于一个项目中处于运行效率关键位置的代码,尽量避免使用反射特性。

射是如何实现的

之前的文章有讲到了 interface,它是 Go 语言实现抽象的一个非常强大的工具。当向接口变量赋予一个实体类型的时候,接口会存储实体的类型信息,反射就是通过接口的类型信息实现的,反射建立在类型的基础上。

Go 语言在 reflect 包里定义了各种类型,实现了反射的各种函数,通过它们可以在运行时检测类型的信息、改变类型的值。

reflect包

在Go语言的反射机制中,任何接口值都由是一个具体类型具体类型的值两部分组成的(我们在之前接口的文章中有介绍相关概念)。在Go语言中反射的相关功能由内置的reflect包提供,任意接口值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成,并且reflect包提供了reflect.TypeOf和reflect.ValueOf两个函数来获取任意对象的Value和Type。

TypeOf

在Go语言中,使用reflect.TypeOf()函数可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息。

package mainimport (  "fmt"  "reflect")func reflectType(x interface{}) {
      v := reflect.TypeOf(x)  fmt.Printf("type:%v\n", v)}func main() {
      var a float32 = 3.14  reflectType(a) // type:float32  var b int64 = 100  reflectType(b) // type:int64}
type name和type kind

在反射中关于类型还划分为两种:类型(Type)种类(Kind)。因为在Go语言中我们可以使用type关键字构造很多自定义类型,而种类(Kind)就是指底层的类型,但在反射中,当需要区分指针、结构体等大品种的类型时,就会用到种类(Kind)。举个例子,我们定义了两个指针类型和两个结构体类型,通过反射查看它们的类型和种类。

package mainimport (  "fmt"  "reflect")type myInt int64func reflectType(x interface{}) {
      t := reflect.TypeOf(x)  fmt.Printf("type:%v kind:%v\n", t.Name(), t.Kind())}func main() {
      var a *float32 // 指针  var b myInt    // 自定义类型  var c rune     // 类型别名  reflectType(a) // type: kind:ptr  reflectType(b) // type:myInt kind:int64  reflectType(c) // type:int32 kind:int32  type person struct {
        name string    age  int  }  type book struct{ title string }  var d = person{
        name: "纽约蜘蛛侠",    age:  18,  }  var e = book{title: "《跟蜘蛛侠学Go语言》"}  reflectType(d) // type:person kind:struct  reflectType(e) // type:book kind:struct}

Go语言的反射中像数组、切片、Map、指针等类型的变量,它们的.Name()都是返回空。

在reflect包中定义的Kind类型如下:

type Kind uintconst (    Invalid Kind = iota  // 非法类型    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值