iris 指针的理解使用及数据库操作层封装
在 Golang 指针 文章中,我们谈及过 Golang 指针的基本信息,但由于篇幅还不够详细。
今天藉由 数据库操作层封装
的实操机会,我们继续了解。
如果在之前接触过其他编程语言:Java、Python、PHP 等,在开发过程中并不会经常使用用到指针
,而在 Golang 中函数的从属
、变量的传递
都有机会用到指针。
于是乎用与不用,为什么需要使用指针?成为开发前必须明确的问题
指针的理解和使用
实践出真知,我们从例子出发,然后解读:
从上面代码中的 setAgeV1
、setAgeV2
函数的结果,我们可以看出指针
的些许端疑
Golang 只有一种变量传递方式:
值传递
、引用传递
。
一个值变量
作为参数
传递时,会被复制
出该变量的副本
,然后将副本传递给对应函数。如果你在函数内对参数&
取址操作,你会发现这个副本(参数)的地址和原来值变量的地址完全不一样
。
而一个指针变量
被作为参数
被引用时,会被复制
出该指针变量的副本(新指针)
,新指针 会和 原指针 指向相同内存地址,
结合例子分析
结合例子一起分析,我们可以得出这样的结论:
•函数 setAgeV1()
中传递的参数为 值变量
,函数修改 student1
的副本,变量作用域只在 函数 setAgeV1()
中;•函数 setAgeV2()
中传递的参数为 指针变量
,指向 student1
地址。函数修改 student1
变量本身。
函数传参使用指针与否
所以函数传参使用指针与否,我们能总结出下面的规律:
•希望 参数 被函数修改,使用指针;相反不要使用指针;•大参数,传参时不希望发生内存拷贝(内存开销),使用指针;相反不要使用指针;
函数返回值使用指针与否
返回值使用值传递
、还是引用传递
标准同上
•希望 返回值 被函数修改,使用指针;相反不要使用指针;•大struct/大数组,返回时不希望发生内存拷贝(内存开销),使用指针;相反不要使用指针;•函数作用域内的参数,使用值传递(不使用指针)
Go编译器会尽量将对象分配到栈上;而引用传递(使用指针)
很可能会分配到对象上,这对垃圾回收会有影响
跳出指针,结合实际分析
我们把上面的例子稍微修改一下,你会发现两种方式都能修改变量:
函数setAgeV1()
是值传递,参数 student 复制参数副本(整个student发生内存拷贝) 进入函数 setAgeV1();修改 student.age
属性;返回修改后的 student ,复制副本(修改后的 student),返回给函数外面
函数setAgeV2()
是引用传递,参数 student 复制参数指针的副本进入函数 setAgeV1();修改 原来的student.age
属性;执行结束
见微知著:不使用指针的是值传递,基本就不会走gc(原理:释放堆中不再使用/引用的对象所占用的空间),缺点是整个struct都发生内存拷贝,而被编译器识别为inline函数就什么都不会发生,性能极好。所以函数输入/返回参数就几个int,float,struct 建议使用值传递
指针就是类似引用传递,出作用域会走gc,当然也不是,比如inline函数返回指针就不一定会导致堆分配,而Golang内置的new和make,map,slice等本身就分配在堆上就必然走gc。
gc对于密集型计算服务的后果就是大量cpu计算都消耗在gc上,严重影响性能;另外栈内存的分配花销时间可能比堆好。而且在实际开发维护中,大范围使用指针会因为不知道数据哪里被更改,而导致代码极难维护。
数据库操作 dao 层
dao/playerinfo_dao.go
来源 https://www.modb.pro/db/71043