Call by value
call by value是指调用函数时,为函数传递的参数是变量的copy,也就是说,函数内部对此参数进行的任何操作在函数外都是不可见,比如:
int inc(int n)
{
printf("address of n: %x\n", (unsigned int)(&n));
n++;
printf("value of n: %d\n", n);
return n;
}
int main()
{
int m = 0;
printf("address of m: %x\n", (unsigned int)(&m));
inc(m);
printf("value of m: %d\n", m);
return 0;
}
// output:
// address of m: ffffcc0c
// address of n: ffffcbe0
// value of n: 1
// value of m: 0
在main
函数中调用inc
时,为inc
传递了变量m
作为参数,但其实在inc
函数内部,n
是m
的一个copy,对n
的任何操作,都不会影响m
的值。
C语言的传参方式为call by value,如果想让函数内对参数的操作影响函数外的变量,就需要使用指针。
int *inc(int *n)
{
printf("value of n: %x\n", (unsigned int)n);
(*n)++;
printf("value of *n: %d\n", (*n));
return n;
}
int main()
{
int m = 0;
printf("address of m: %x\n", (unsigned int)&m);
inc(&m);
printf("value of m: %d\n", m);
return 0;
}
// output:
// address of m: ffffcc0c
// value of n: ffffcc0c
// value of *n: 1
// value of m: 1
在上面的代码中,将变量m
的地址值的copy传递给n
,那么对n
指向的内容进行操作,就相当于对变量m
进行了操作。
Call By Reference
call by reference是指调用函数时,传递给函数的参数是变量的reference,而不是变量的copy,这意味着函数可以操作作为参数的变量,而且这些修改对调用者是可见的。
Call By Sharing
call by sharing暗示着这种语言中的值是基于对象而不是原始值,也就是说,所有的值都是一种对象,有自己的属性或方法。
1. 以mutable object作为参数
如果作为参数传给函数的变量是可变的,那么在函数中对这个参数的更改对调用者来说是可见的。这是因为在向函数传参时,函数体中的形参被绑定到传给函数的参数所绑定的对象上,这时这个对象是被共享的。
def append_1(l):
print("id of l: ", id(l)) # id(l) == id(m)
l.append(1)
print("id of l: ", id(l)) # id(l) == id(m)
m = []
print("id of m: ", id(m))
append_1(m)
print("value of m: ", m) # [1]
# output:
# id of m: 1393538893832
# id of l: 1393538893832
# id of l: 1393538893832
# value of m: [1]
在以上代码中,当函数被调用时,变量l
与变量m
绑定到同一个对象上(id(l) == id(m)
),所以对l
的修改会影响到m
。
但是在函数体中对其形参进行赋值时,这个操作对调用者是不可见的。这是因为赋值操作会把这个形参绑定到另一个对象上,而不是改变这个原有对象。而对调用者来说,变量的绑定没有改变。
def asg_1(l):
print("id of l: ", id(l)) # id(l) == id(m)
l = [1]
print("id of l: ", id(l)) # id(l) != id(m)
m = []
print("id of m: ", id(m))
asg_1(m)
print("value of m: ", m) # []
# output:
# id of m: 1393539676232
# id of l: 1393539676232
# id of l: 1393539049672
# value of m: []
在以上代码中,因为asg_1
内存在赋值操作l = [1]
,导致变量l
重新绑定到另一个对象上,而m
变量所绑定的对象并没有改变。
2. 以immutable object作为参数
对于不可变对象,在call by sharing与call by value之间没有真正的不同。
3. JavaScript和Python中的对象
JavaScript和Python的参数传递方式都是call by sharing,所以要判断函数是否会对参数造成调用者可见的影响时,只要根据传入参数是否为可变对象即可。以下是JavaScript和Python中的mutable object和immutable object:
JavaScript | Python | |
---|---|---|
mutable object |
Object(Function, Date, Array, RegExp) |
dictionary, list |
immutable object |
Boolean, Null, Undefined, Number, Symbol, String |
tuple, number, string |
- older
- Newer