0%

为什么代码中实例化结构体时大多要返回结构体指针 而不是结构体值

在学习 go 语言项目时,遇到这样一个问题:

通过struct结构体作为一个model,数据绑定等操作都是返回一个结构体指针,那么返回一个结构体变量,或者返回一个结构体指针,他们的区别是什么?

因为二者都可以让我们生成我们所需要的结构体,那为什么还要去使用返回结构体指针呢

对于此疑问,我做了如下实验


// TableFile : 文件表结构体
type TableFile struct {
	FileHash string
	FileName string
	FileSize string
	FileAddr string
}

// GetFileMeta1  从mysql获取文件元信息
func GetFileMeta1(filehash1 string) *TableFile {

	tfile1 := TableFile{FileHash: filehash1}
	fmt.Printf("GetFileMeta1函数内:%p\n", &tfile1)
	return &tfile1
}

// GetFileMeta2  从mysql获取文件元信息
func GetFileMeta2(filehash1 string) TableFile {

	tfile2 := TableFile{FileHash: filehash1}
	fmt.Printf("GetFileMeta2函数内:%p\n", &tfile2)
	return tfile2
}


// GetFileMeta3 从mysql获取文件元信息
func GetFileMeta3(filehash1 string) (tfile3 TableFile) {

	tfile3 = TableFile{FileHash: filehash1}
	fmt.Printf("GetFileMeta3函数内:%p\n", &tfile3)
	return
}
func main() {
	t1 := GetFileMeta1("1111")
	fmt.Printf("GetFileMeta1  函数外%p\n", t1)
	t2 := GetFileMeta2("1111")
	fmt.Printf("GetFileMeta2  函数外%p\n", &t2)
	t3 := GetFileMeta3("1111")
	fmt.Printf("GetFileMeta3  函数外%p\n", &t3)

}

//GetFileMeta1函数内:0xc00005a040
//GetFileMeta1  函数外0xc00005a040

//GetFileMeta2函数内:0xc00005a0c0
//GetFileMeta2  函数外0xc00005a080

//GetFileMeta3函数内:0xc00005a140
//GetFileMeta3  函数外0xc00005a100

这里可以发现:

  • 使用指针结构体只分配了一次内存
  • 使用结构体值却分配了两次

由于go是值拷贝模式,指针拷贝地址,没有分配多余内存;值拷贝数值,新的变量会重新分配地址给数值。

这一点了解了,可是我仍然不知道指针的性能提升在那里,虽然指针只分配了一次地址空间,可是该空间会分配在堆上发生内存逃逸,影响程序性能;

值空间虽然分配了两次空间,但函数内变量空间分配在栈上,函数结束,系统内核会自动销毁,不影响性能,?难道是多次分配调度内存空间,影响更大?

返回结构体值与结构体指针性能问题:

传值 VS 传指针: 传值会拷贝整个对象,而传指针只会拷贝指针地址,指向的对象是同一个。传指针可以减少值的拷贝,但是会导致内存分配逃逸到堆中,增加垃圾回收(GC)的负担。在对象频繁创建和删除的场景下,传递指针导致的 GC 开销可能会严重影响性能。

一般情况下,对于需要修改原对象值,或占用内存比较大的结构体,选择传指针。对于只读的占用内存较小的结构体,直接传值能够获得更好的性能

-------------本文结束感谢您的阅读-------------
打赏一瓶矿泉水