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内部保存的类型信息
相关推荐
会敲键盘的猕猴桃很大胆14 分钟前
Redis实战-基于redis和lua脚本实现分布式锁以及Redission源码解析【万字长文】
java·redis·分布式·spring·lua
设计师小聂!1 小时前
JDBC+HTML+AJAX实现登陆和单表的CRUD
java·ajax·servlet·html·maven
Mr__Miss1 小时前
微服务中引入公共拦截器
java·微服务·架构
刘大浪1 小时前
JDK17 与JDK8 共同存在一个电脑上
java
gou123412341 小时前
【Golang进阶】第八章:并发编程基础——从Goroutine调度到Channel通信实战
开发语言·后端·golang
秋难降1 小时前
贪心算法:看似精明的 “短视选手”,用好了也能逆袭!💥
java·算法
阿蒙Amon2 小时前
C#数字金额转中文大写金额:代码解析
java·mysql·c#
失乐园2 小时前
电商/物流/IoT三大场景:用MongoDB设计高扩展数据架构的最佳实践
java·后端·架构
五行星辰2 小时前
Spring AI 实战:用 Java 搞 AI,从此告别调参侠
java·后端
知其然亦知其所以然2 小时前
不懂 Python?没关系!Easy RAG 让 Java 开发者也能玩转大模型
java·后端·llm