golang -- 如何获取变量类型

目录

前言

在学习反射的时候,对reflect包中获取变量类型的函数很迷惑

比如下面这个 用Type获取变量类型的方法(在下面提到)

所以结合多方资料进行了学习,并整理了这篇博客

获取变量类型

一、fmt.Printf

直接使用 fmt.Printf 的 %T 打印变量的类型

go 复制代码
	fmt.Printf("%T\n", 1)     //int
	fmt.Printf("%T\n", "abc") //string
	fmt.Printf("%T\n", true)  //bool
	fmt.Printf("%T\n", 1.1)   //float64

二、类型断言

类型断言是Go语言中用于检查接口值的底层具体类型或将其转换为特定类型的机制。它允许从接口值中提取出具体的值,或者检查接口值是否持有特定的类型

  • 基本语法
    类型断言有两种形式:
  1. 单返回值形式:x.T( )
  2. 双返回值形式:value, ok := x.T( )
  • 单返回值形式
go 复制代码
value := x.(T)
  1. 参数:
  • x:必须是一个接口类型的表达式
  • T:要断言的类型(可以是具体类型或另一个接口类型)
  1. 返回值:
  • 如果 x 是 T 类型,则返回 x 的值
  • 如果 x 不是 T 类型,则断言失败,会引发 panic

*** 示例:

断言成功:

go 复制代码
	a := 1
	v := interface{}(a)
	value := v.(int)   //断言成功
	fmt.Println(value) //输出1

断言失败:

go 复制代码
	a := 1
	v := interface{}(a)
	value := v.(float64) //断言失败,引发panic
	fmt.Println(value)

panic: interface conversion: interface {} is int, not float64

  • 双返回值形式
go 复制代码
value, ok := x.(T)
  1. 参数:

    同单返回值形式

  2. 返回值:

  • value:如果断言成功,返回 x 的值(实际上这里存在一个类型转换,x是接口类型的变量,首先将值从interface{ }类型转换为T类型,再赋值给value);否则返回 T 类型的零值
  • ok:bool值,如果断言成功是true,断言失败是false

示例:

go 复制代码
	value, ok := v.(string)   //断言失败
	fmt.Println(value, ok)    //输出" false"  这里value不是没有输出,而是因为value是string的零值 输出空字符串
	fmt.Printf("%T\n", value) //输出"string"--表明value是string类型的零值
	value1, ok1 := v.(int)    //断言成功
	fmt.Println(value1, ok1)  //输出"1 true"
  1. 忽略返回值的规则
  • 忽略ok(只关心值)
go 复制代码
value, _ := x.(T)   //忽略ok

风险:如果断言失败,value是T类型的零值,可能引发逻辑错误

  • 忽略value (只检查类型)
    如果只关心类型是否匹配,不关心具体值:
go 复制代码
_,ok := x.(T)  //忽略value

三、类型选择

类型选择是Go语言中一种特殊的 switch 语句,用于检查接口值的动态类型。

必须和switch一起使用

  • 基本语法:
go 复制代码
	switch v := x.(type) {
	case T1:
	//v的类型是T1
	case T2:
	//v的类型是T2
	default:
	}
  1. 参数
    必须是接口类型

*** 示例:

go 复制代码
	a := 1
	v := interface{}(a)
	switch v.(type) {
	case int:
		fmt.Println("int类型")
	case string:
		fmt.Println("是string类型")
	default:
		fmt.Println("未知")
	}

输出

go 复制代码
int

四、反射 reflect.TypeOf

reflect.TypeOf 是Go语言标准库中 reflect 包提供的核心函数之一,用于获取任意值的类型信息

  • 基本语法:
go 复制代码
// TypeOf returns the reflection [Type] that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i any) Type {
	return toType(abi.TypeOf(i))
}
go 复制代码
//TypeOf 返回表示 i 的动态类型的反射 [Type]。
//如果 i 是 nil 接口值,则 TypeOf 返回 nil。
  1. 参数
  • 接收参数:

    接收任意 类型的值(实际上存在类型转换,在底层实现原理提到)

  • 参数传递机制:

    如果是值类型(如int、struct 等),会创建值的副本

    如果是引用类型(如slice、map、pointer等),会复制引用

  1. 返回值
  • 返回值类型: reflect.Type(接口类型)
  • 返回值内容:
    包含动态类型信息
    可以获取类型名称、种类(Kind)、方法集等
  1. 底层实现原理:
go 复制代码
func TypeOf(i interface{}) Type 
  • 调用TypeOf(x) 时:
    编译器将x转换为接口值 (包含类型指针和值指针)
    运行时从接口值中提取类型信息
    返回指向内部类型结构的 reflect.Type 接口
  • 类型描述符:
    Go运行时为每种类型维护一个类型描述符(rtype)

*** 示例:

  • 对于基本类型,
go 复制代码
	a := "bcd"
	fmt.Println(reflect.TypeOf(a)) //输出:string
  • 对于结构体变量,
go 复制代码
type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{
		"haha",
		18,
	}
	t := reflect.TypeOf(p)  
	fmt.Println(t)

	//遍历结构体中所有字段
	for i := 0; i < t.NumField(); i++ { //NumField计算结构体字段个数
		field := t.Field(i) //每个字段的类型和值
		fmt.Println(field.Name, field.Type) //field.Type和field.Kind在下面提到
	}
}

输出如下

go 复制代码
main.Person
Name string
Age int

field.Name 和 field.Type

在Go语言的反射机制中,

field.Name 和 field.Type 是用于描述结构体字段的两个关键属性,

field.Name获取字段名,field.Type获取字段类型


五、reflect.Value的Type()方法

已经有一个reflect.Value 时,可以通过它的Type()方法 获取类型

参数必须是Value类型

*** 示例:

go 复制代码
	v := reflect.ValueOf(3)
	t := v.Type()       //从Value获取Type
	fmt.Println(t)      //输出"int"

reflect.TypeOf(x) 和 v.Type() 的区别

  1. 接收参数
    reflect.TypeOf(x) :参数可以为任意类型
    v.Type() :参数为Value类型
  2. 底层实现
    reflect.TypeOf(x)内部会先创建一个interface{},然后提取类型信息
    v.Type()只是返回reflect.Value内部保存的类型信息
相关推荐
Dcs20 分钟前
用不到 1000 行 Go 实现 BaaS,Pennybase 是怎么做到的?
java
Cyanto2 小时前
Spring注解IoC与JUnit整合实战
java·开发语言·spring·mybatis
qq_433888932 小时前
Junit多线程的坑
java·spring·junit
gadiaola2 小时前
【SSM面试篇】Spring、SpringMVC、SpringBoot、Mybatis高频八股汇总
java·spring boot·spring·面试·mybatis
写不出来就跑路2 小时前
WebClient与HTTPInterface远程调用对比
java·开发语言·后端·spring·springboot
Cyanto2 小时前
深入MyBatis:CRUD操作与高级查询实战
java·数据库·mybatis
麦兜*3 小时前
Spring Boot 集成Reactive Web 性能优化全栈技术方案,包含底层原理、压测方法论、参数调优
java·前端·spring boot·spring·spring cloud·性能优化·maven
天上掉下来个程小白3 小时前
MybatisPlus-06.核心功能-自定义SQL
java·spring boot·后端·sql·微服务·mybatisplus
知了一笑3 小时前
独立开发第二周:构建、执行、规划
java·前端·后端
小李飞飞砖3 小时前
Sophix、Tinker 和 Robust 三大主流 Android 热修复框架的详细对比
android