这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战
参数传递
分为两种:值传递、引用传递
go选择了值传递,在进行参数传递的时候会进行拷贝操作,包括指针,不过即使指针的值发生了备份(指针自己的地址发生了改变),还是可以通过解引用的方式来进行指针指向值全局修改
当传入的结构体很大的时候,会影响调用性能
接口(interface)
引入中间层,通过中间层的方式解藕上下游依赖
go中不需要显示地声明实现的接口,只要实现了对应接口的方法就视为实现了对应接口,仅在必要时进行检测
interface本身也是一种类型,并不代表无类型
package main
type TestStruct struct{}
func NilOrNot(v interface{}) bool {
return v == nil
}
func main() {
var s *TestStruct
fmt.Println(s == nil) // #=> true
fmt.Println(NilOrNot(s)) // #=> false
}
在这进行参数传递的时候,会进行nil转换成interface,interface的内容会变成nil,并且拥有原来结构的类型信息,但是interface本身不是nil
interface也有两种类型:
- Iface:带有方法的接口
type iface struct { // 16 字节
tab *itab
data unsafe.Pointer // 指向数据
}
- eface:不带有任何方法的接口
type eface struct { // 16 字节
_type *_type // 指向类型
data unsafe.Pointer // 指向数据
}
_type:
表示一个结构的类型
type _type struct {
size uintptr // 使用的内存大小
ptrdata uintptr
hash uint32 // 用于判断类型是否相等
tflag tflag
align uint8
fieldAlign uint8
kind uint8
equal func(unsafe.Pointer, unsafe.Pointer) bool
// 可用于快速判断当前类型的多个对象数据是否相等
gcdata *byte
str nameOff
ptrToThis typeOff
}
itab:
更为复杂,可以看作是接口类型与具体类型的结合
type itab struct { // 32 字节
inter *interfacetype
_type *_type
hash uint32 // _type中hash的拷贝,用于快速判断能否进行类型转换
_ [4]byte
fun [1]uintptr //动态派发的虚函数表,内部为函数指针
}
interface有定义方法的时候,将结构体转换成interface,会将data进行直接拷贝,将类型指针从run time中获取
两者的转换过程如下
关于结构体与指针
- 结构体与指针都可以实现方法,指针可以调用结构体实现、但指针没有实现的方法,反之则不行
指针变量可以隐式获取指向的对应结构体,然后再进行函数方法调用
因此当结构体实现函数方法时,指针都可视为实现了该方法
反射
go可以通过反射获取变量的类型和值并且进行修改,类似元编程
- Typeof:获取类型信息,包装为reflect.Type类型
- Valueof:获取值信息,包装为reflect.Value类型
元编程
是指某类计算机程序的编写,这类计算机程序编写或者操纵其它程序(或者自身)作为它们的资料,或者在运行时完成部分本应在编译时完成的工作。多数情况下,与手工编写全部代码相比,程序员可以获得更高的工作效率,或者给与程序更大的灵活度去处理新的情形而无需重新编译。
第一法则:
关于获取变量(转换成interface后)的内部信息,对于指针变量可以通过.elem()方法获取指向的值信息,另外reflect.Value本身也是有基本类型信息的
\
type emptyInterface struct {
typ *rtype
word unsafe.Pointer
}
Value的结构:
type Value struct {
typ *rtype // 当前结构数据基本类型信息
ptr unsafe.Pointer // 数据指针
flag
}
Type的结构(这里以interface为例):
type interfaceType struct {
rtype // 当前结构基本类型信息
pkgPath name // import path
methods []imethod // sorted by hash
}
第二法则:
可以从reflect_object转换成interface,然后通过显示声明转换为原来的类型
第三法则:
和其他语言一样,只有通过指针才能够修改原有变量的值,否则只是值拷贝的修改,因此只有获取原有变量的指针,然后通过elem方法获取指针指向的值,然后进行修改(使用.Set()方法)才能更新原来变量的reflect.Value
其他
- 可以通过reflect.Type.Implements()方法判断是否实现了某些interface中规定的接口
- ValueOf的对象选择有很多,几乎所有类型都可以使用该方法
- reflect中还有很多其他的方法,如
-
- reflect.Type.Elem()可以获得当前结构的内部子数据(有子数据,如map中的数据)的Type信息
- reflect.Type.Elem()可以获得当前结构(为指针)指向的数据
Type强调的是类型信息及其相关,如类型内部的函数、域等
Value强调的是值信息及其相关,如值的类型、值的内容等
- 个人理解,就像c++一样,Type更强调的是类本身的信息,Value强调的是对象的信息