引用传递来源于C++。在 C++中,函数参数的传递方式有引用传递。所谓引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
总结
引用传递时,在函数内部修改该值,当函数执行完成后,函数内部的对该值修改会被保留下来,
Java | 值 |
JavaScript | 值 |
Go | 值 |
C++ | 可值/可引用 |
C | 值 |
Python | 值 |
| |
为什么是这个结果可以接着往下看。
按值/引用传递的本质
首先要理解按值传递与按引用传递到底是啥,本质是啥
这里之所以采用C++
,是因为引用传递一词也源于C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include "iostream"
using std::cout; using std::endl;
struct Person { int age; Person(int age): age(age) {} };
void passByValue(int a, Person p, Person *p2) { a++; p.age++; p2->age++; }
void passByReference(int &a, Person &p, Person *&p2) { a++; p.age++; p2->age++; }
int main() { int a = 0; Person p(20); Person *p2 = new Person(30); cout <<"before passByValue(a, p)\na:" << a << " p.age:" << p.age << " p2.age:" << p2->age << endl; passByValue(a, p, p2); cout << "after passByValue(a, p)\na:" << a << " p.age:" << p.age << " p2.age:" << p2->age << endl;
cout <<"before passByReference(a, p)\na:" << a << " p.age:" << p.age << " p2.age:" << p2->age << endl; passByReference(a, p, p2); cout << "after passByReference(a, p)\na:" << a << " p.age:" << p.age << " p2.age:" << p2->age << endl; return 0; }
|
可以看到按引用传递时,不管传递的简单类型,还是结构体,还是指针,在函数内部的修改都会改变原来的值。
按值传递时,只有当参数传递的是一个指针时,在函数内部的修改并且是对才是对原始值的修改。
如何理解其他语言的(类引用传递)?
这里以JavaScript
和Go
来举例
1 2 3 4 5 6 7 8 9
| function modify(taget, key, val) { taget[key] = val } const o = { age: 12, } console.log(o) modify(o, 'age', 13) console.log(o)
|
这里调用modify
对o
的age
属性进行修改,并且外部的原始值也进行了修改,但是第 3 行的修改却没有生效。
如果是按值传递,那内部的任何修改都不会对外部有影响,如果是按引用传递,那为什么没有变成{name: 'Tidi'}
当我们再看看 C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include "iostream"
using std::cout; using std::endl;
struct Person { int age; Person(int age): age(age) {} };
void passByValue(int a, Person p, Person *p2) { a++; p.age++; p2->age++;
p = Person(40); p2 = new Person(50); }
void passByReference(int &a, Person &p, Person *&p2) { a++; p.age++; p2->age++;
p = Person(40); p2 = new Person(50); }
int main() { int a = 0; Person p(20); Person *p2 = new Person(30); cout <<"before passByValue(a, p, p2)\na:" << a << " p.age:" << p.age << " p2.age:" << p2->age << endl; passByValue(a, p, p2); cout << "after passByValue(a, p, p2)\na:" << a << " p.age:" << p.age << " p2.age:" << p2->age << endl;
cout <<"before passByReference(a, p, p2)\na:" << a << " p.age:" << p.age << " p2.age:" << p2->age << endl; passByReference(a, p, p2); cout << "after passByReference(a, p, p2)\na:" << a << " p.age:" << p.age << " p2.age:" << p2->age << endl; return 0; }
|
这次在两个函数内部我们不仅对 Person 的 age 修改进行修改,也对整个 p 进行了修改。可以发现,只有引用传递的时候,最后对 p 的修改才会影响到外部。
而值传递时,当对指针的某个属性进行修改时,才会影响外部。
然后用JavsScript
实现上面的实验
是不是可以这样理解,JavaScript
的对象在传递是其实传递的是该对象的对应指针,而且这正好和JavaScript
的对象其实的变量其实是一个指针的概念相统一。
所以JavaScript
的函数是按值传递的。