Ruby使用“按对象传递引用”
(使用Python的术语。)
说Ruby使用“按值传递”或“按引用传递”并不能真正起到描述作用。我认为,如今大多数人都知道,术语(“值”与“引用”)来自C ++。
在C ++中,“按值传递”表示函数获取变量的副本,并且对该副本的任何更改都不会更改原始变量。对象也是如此。如果按值传递对象变量,则将复制整个对象(包括其所有成员),并且对成员的任何更改都不会更改原始对象上的那些成员。(如果您按值传递指针,但Ruby仍然没有指针,则不同,AFAIK。)
class A {
public:
int x;
};
void inc(A arg) {
arg.x++;
printf("in inc: %d\n", arg.x); // => 6
}
void inc(A* arg) {
arg->x++;
printf("in inc: %d\n", arg->x); // => 1
}
int main() {
A a;
a.x = 5;
inc(a);
printf("in main: %d\n", a.x); // => 5
A* b = new A;
b->x = 0;
inc(b);
printf("in main: %d\n", b->x); // => 1
return 0;
}
输出:
in inc: 6
in main: 5
in inc: 1
in main: 1
在C ++中,“按引用传递”表示函数可以访问原始变量。它可以分配一个新的立即数整数,然后原始变量也将具有该值。
void replace(A &arg) {
A newA;
newA.x = 10;
arg = newA;
printf("in replace: %d\n", arg.x);
}
int main() {
A a;
a.x = 5;
replace(a);
printf("in main: %d\n", a.x);
return 0;
}
输出:
in replace: 10
in main: 10
如果参数不是对象,则Ruby使用按值传递(在C ++中)。但是在Ruby中,所有事物都是对象,因此在Ruby中C ++的意义上确实没有按值传递。
在Ruby中,使用“通过对象引用传递”(以使用Python的术语):
- 在函数内部,对象的任何成员都可以分配有新值,并且这些更改将在函数返回后保留。
- 在函数内部,为变量分配一个新对象会导致该变量停止引用旧对象。但是在函数返回后,原始变量仍将引用旧对象。
因此,Ruby在C ++的意义上不使用“按引用传递”。如果确实如此,则在函数内部将新对象分配给变量后,将导致在函数返回后忘记旧对象。
class A
attr_accessor :x
end
def inc(arg)
arg.x += 1
puts arg.x
end
def replace(arg)
arg = A.new
arg.x = 3
puts arg.x
end
a = A.new
a.x = 1
puts a.x # 1
inc a # 2
puts a.x # 2
replace a # 3
puts a.x # 2
puts ''
def inc_var(arg)
arg += 1
puts arg
end
b = 1 # Even integers are objects in Ruby
puts b # 1
inc_var b # 2
puts b # 1
输出:
1
2
2
3
2
1
2
1
*这就是为什么在Ruby中,如果您想修改函数内部的对象,但是在函数返回时忘记了这些更改,那么您必须在对副本进行临时更改之前显式创建该对象的副本。