루비는 "객체 참조로 전달"을 사용합니다
(Python 용어 사용)
루비가 "값으로 전달"또는 "참조로 전달"을 사용한다고 말하는 것은 실제로 설명하기에 충분하지 않습니다. 요즘 대부분의 사람들이 알고 있듯이 그 용어 ( "value"대 "reference")는 C ++에서 온 것입니다.
C ++에서 "pass by value"는 함수가 변수의 사본을 가져오고 사본을 변경해도 원본이 변경되지 않음을 의미합니다. 객체에도 마찬가지입니다. 값으로 객체 변수를 전달하면 전체 객체 (모든 멤버 포함)가 복사되고 멤버를 변경해도 원래 객체의 해당 멤버는 변경되지 않습니다. (값으로 포인터를 전달하지만 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 ++에서 "pass by reference"는 함수가 원래 변수에 액세스하는 것을 의미합니다. 완전히 새로운 리터럴 정수를 할당하면 원래 변수도 그 값을 갖습니다.
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 ++ 의미). 그러나 루비에서는 모든 것이 객체이므로 루비에서는 C ++ 의미의 가치가 실제로 없습니다.
Ruby에서는 "객체 참조를 통한 전달"(Python 용어를 사용하기 위해)이 사용됩니다.
- 함수 내에서 객체의 모든 멤버에 새 값을 할당 할 수 있으며 이러한 변경 사항은 함수가 반환 된 후에도 유지됩니다. *
- 함수 내에서 완전히 새로운 객체를 변수에 할당하면 변수가 이전 객체 참조를 중지합니다. 그러나 함수가 반환 된 후에도 원래 변수는 여전히 이전 개체를 참조합니다.
따라서 루비는 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에서 함수 내부의 오브젝트를 수정하고 함수가 리턴 될 때 해당 변경 사항을 잊어 버리려면 임시로 사본을 변경하기 전에 오브젝트를 명시 적으로 복사해야합니다.