使用建议
那我们在什么时候使用指针呢?有以下几点建议:
- 如果参数是基本的值类型,比如
int,float
建议直接传值。
- 如果需要修改基本的值类型,那只能是指针;但考虑到代码可读性还是建议将修改后的值返回用于重新赋值。
- 数据量较大时建议使用指针,减少不必要的值拷贝。(具体多大可以自行判断)
Python
在 Python
中变量是否可变是影响参数传递的重要因素:
网络异常,图片无法展示
|
如上图所示,bool int float
这些不可变类型在参数传递过程中是不能修改原始数据的。
if __name__ == '__main__': x = 1 modify(x) print('最终 x={}'.format(x)) def modify(val): val = 2 最终 x=1
原理与 Java Go
中类似,是基于值传递的,这里就不再复述。
这里重点看看可变数据类型在参数传递中的过程:
if __name__ == '__main__': x = [1] modify(x) print('最终 x={}'.format(x)) def modify(val): val.append(2) 最终 x=[1, 2]
最终数据受到了影响,那么就表明这是引用传递嘛?再看个例子试试:
if __name__ == '__main__': x = [1] modify(x) print('最终 x={}'.format(x)) def modify(val): val = [1, 2, 3] 最终 x=[1]
显而易见这并不是引用传递,如果是引用传递最终 x
应当等于 [1, 2 ,3]
。
从结果来看这个传递过程非常类似 Go
中的指针传递,val
拿到的也是 x
这个参数内存地址的拷贝;他们都指向了同一块内存地址。
所以对这块数据的修改本质上改的是同一份数据,但一旦重新赋值就会创建一块新的内存从而不会影响到原始数据。
网络异常,图片无法展示
|
与 Java
中的上图类似。
所以总结下:
- 对于不可变数据:在参数传递时传递的是值,对参数的修改不会影响到原有数据。
- 对于可变数据:传递的是内存地址的拷贝,对参数的操作会影响到原始数据。
这么说来这三种都是值传递了,那有没有引用传递的语言呢?
当然,C++
是支持引用传递的:
#include <iostream> using namespace std; class Box { public: double len; }; void modify(Box& b); int main () { Box b1; b1.len=100; cout << "调用前,b1 的值:" << b1.len << endl; modify(b1); cout << "调用后,b1 的值:" << b1.len << endl; return 0; } void modify(Box& b) { b.len=10.0; Box b2; b2.len = 999; b = b2; return; } 调用前,b1 的值:100 调用后,b1 的值:999
可以看到把新对象 b2
赋值给入参 b
后是会影响到原有数据的。
总结
其实这几种语言看下来会发现他们中也有许多相似之处,所以通常我们在掌握一门语言后也能快速学习其他语言。
但往往是这些基础中的基础最让人忽略,希望大家在日常编码时能够考虑到这些基础知识多想想一定会写出更漂亮的代码(bug)。