0%

引用传递与值传递

引用传递来源于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;
}

16369588041454MgQgr

可以看到按引用传递时,不管传递的简单类型,还是结构体,还是指针,在函数内部的修改都会改变原来的值。

按值传递时,只有当参数传递的是一个指针时,在函数内部的修改并且是对才是对原始值的修改。

如何理解其他语言的(类引用传递)?

这里以JavaScriptGo 来举例

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)
163695930858221lzXA

这里调用modifyoage属性进行修改,并且外部的原始值也进行了修改,但是第 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;
}
1636959505689AGTwEf

这次在两个函数内部我们不仅对 Person 的 age 修改进行修改,也对整个 p 进行了修改。可以发现,只有引用传递的时候,最后对 p 的修改才会影响到外部。

而值传递时,当对指针的某个属性进行修改时,才会影响外部。

然后用JavsScript实现上面的实验

1636959908863u6AiTq

是不是可以这样理解,JavaScript的对象在传递是其实传递的是该对象的对应指针,而且这正好和JavaScript的对象其实的变量其实是一个指针的概念相统一。

所以JavaScript的函数是按值传递的。