反射面试题
反射面试题
1. 什么是反射?
反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
2. Go语言如何实现反射?
Go语言反射是通过接口来实现的,一个接口变量包含两个指针结构:一个指针指向类型信息,另一个指针指向实际的数据。当我们将一个具体类型的变量赋值给一个接口时,Go就会把这个变量的类型信息和数据地址都存到这个接口变量里。
有了这个前提,Go语言就可以通过再由reflect
包的Type
和ValueOf
这两个函数读取接口变量里的类型信息和数据信息。把这些内部信息“解包”成可供我们检查和操作的对象,完成在运行时对程序本身的动态访问和修改
3. Go语言中的反射应用有哪些
JSON序列化是最常见的应用,像encoding/json
包通过反射动态获取结构体字段信息,实现任意类型的序列化和反序列化。这也是为什么我们能直接用json.Marshal
处理各种自定义结构体的原因。
ORM框架是另一个重点应用,比如GORM通过反射分析结构体字段,自动生成SQL语句和字段映射。它能动态读取struct tag来确定数据库字段名、约束等信息,大大简化了数据库操作。
Web框架的参数绑定也大量使用反射,像Gin框架的ShouldBind
方法,能够根据请求类型自动将HTTP参数绑定到结构体字段上,这背后就是通过反射实现的类型转换和赋值。
还有配置文件解析、RPC调用、测试框架等场景。比如Viper配置库用反射将配置映射到结构体,gRPC通过反射实现服务注册和方法调用。
4. 如何比较两个对象完全相同
最直接的是用reflect.DeepEqual,这是标准库提供的深度比relatively方法,能递归比较结构体、切片、map等复合类型的所有字段和元素。比如reflect.DeepEqual(obj1, obj2)
,它会逐层比较内部所有数据,包括指针指向的值。
对于简单类型可以直接用==操作符,但这只适合基本类型、数组、结构体等可比较类型。需要注意slice、map、function这些类型是不能直接用==比较的,会编译报错。
实际项目中更推荐自定义Equal方法,根据业务需求定义相等的标准。比如对于用户对象,可能只需要比较ID和关键字段,而不需要比较时间戳这种辅助字段。这样既提高了性能,又符合业务语义。