Rubyは「オブジェクト参照による受け渡し」を使用します
(Pythonの用語を使用しています。)
Rubyが「値による受け渡し」または「参照による受け渡し」を使用していると言うのは、実際に役立つほど十分に説明的ではありません。最近、ほとんどの人が知っているように、その用語( "値"と "参照")はC ++に由来しています。
C ++では、「値渡し」とは、関数が変数のコピーを取得し、そのコピーを変更しても元の変数は変更されないことを意味します。これはオブジェクトにも当てはまります。オブジェクト変数を値で渡すと、オブジェクト全体(そのメンバーのすべてを含む)がコピーされ、メンバーを変更しても、元のオブジェクトのメンバーは変更されません。(値によってポインターを渡すかどうかは異なりますが、Rubyにはとにかくポインターがありません。
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で関数内のオブジェクトを変更したいが、関数が戻ったときにそれらの変更を忘れたい場合は、コピーに一時的な変更を加える前に、オブジェクトのコピーを明示的に作成する必要がある理由です。