今日から4章(p.55~)に入ります。「参照渡しと値渡し(pass by reference, pass by value)」とは、今までにやった内容をさらに深く踏み込むようなタイトルがついている章ですね。この章で主に説明されているのはオブジェクトの渡し方についてです。すごくワクワクします。うん。それでははじまりはじまり。
Rubyの場合
- 参照渡し
- 値渡しその1:浅いコピー(shallow copy)
- 値渡しその2:深いコピー(deep copy)
Rubyの場合は、基本は参照渡しです。本に記載されているスクリプトを抜粋します。
% irb --prompt simple >> def foo(str); str.chop!; end >> my_str = "Hello, World." >> foo(my_str) >> my_str => "Hello, World" >> foo(my_str) >> my_str => "Hello, Worl"
foo(my_str)とすると、my_strの内容が複製されて渡されるわけじゃなく、my_strの参照が渡されます。chop!ってのはStringクラスのメソッドで、文字列の最後の1文字を取り除きます。chop!は、渡されたオブジェクトの内容を書き換えますので、foo(my_str)でmy_strの方も変わっちゃうということです。(!がメソッド名の末尾についているやつは、大抵自分自身の内容を直接変えるやつのようです。)
ちなみに、代入も参照の代入なので
my_str = "Hello, World." my_str2 = my_str my_str2.chop!
とすると、my_strも変わりますね。
値渡しをしたいときは、dupで複製を作って渡すようです。以下も本からの抜粋です。
>> my_str = "Hello, World." >> foo(my_str.dup) => "Hello, World" >> my_str => "Hello, World." >> foo(my_str.dup) => "Hello, World" >> my_str => "Hello, World."
はい、出来ました。なお、dupはオブジェクトを複製するメソッドですが、浅くコピる(インスタンス変数などまでは複製しない)ようです。2章で本に登場したReminderクラスを使って試してみます。Reminderクラスとは、本のp.16に載っているreminder0.rbのことです。今回はRubyの実験なのでdRubyは使いませんよ。
irb(main):002:0> r = Reminder.new
=> #<Reminder:0x2927ce4 @serial=0, @item={}>
irb(main):003:0> r.add('hogehoge')
=> 1
irb(main):004:0> r.to_a
=> 1, "hogehoge"
irb(main):005:0> r2 = r.dup
=> #<Reminder:0x29a1abc @serial=1, @item={1=>"hogehoge"}>
irb(main):006:0> r.__id__
=> 21577330
irb(main):007:0> r2.__id__
=> 21826910
irb(main):008:0> r[1].__id__
=> 21564760
irb(main):009:0> r2[1].__id__
=> 21564760
irb(main):010:0> r2.delete 1
=> "hogehoge"
irb(main):011:0> r.to_a
=> []
irb(main):012:0> r2.to_a
=> []
r(Reminderのインスタンス)と、rをdupして作成したr2はそれぞれ別のIDになっていますが、インスタンス変数である@itemの各要素までは複製されていないため同じIDを返します。なので、r2で要素を消すとrにも影響を与えます。
Rubyで深いコピーを実現したいときには、Marshalを使うようです。Marshalはオブジェクトを文字列に書き出したり、それらからオブジェクトに復元したりするもの(モジュール)です(http://www.ruby-lang.org/ja/man/?cmd=view;name=Marshal)
先ほどirbで書いたスクリプトでdupしている部分をMarshalに変えてみます。
irb(main):003:0> r = Reminder.new
=> #<Reminder:0x2921498 @serial=0, @item={}>
irb(main):004:0> r.add('hogehoge')
=> 1
irb(main):005:0> r.to_a
=> 1, "hogehoge"
irb(main):006:0> r2 = Marshal.load(Marshal.dump(r))
=> #<Reminder:0x2999e0c @serial=1, @item={1=>"hogehoge"}>
irb(main):007:0> r.__id__
=> 21563980
irb(main):008:0> r2.__id__
=> 21810950
irb(main):009:0> r[1].__id__
=> 21832900
irb(main):010:0> r2[1].__id__
=> 21810890
irb(main):011:0> r2.delete 1
=> "hogehoge"
irb(main):012:0> r.to_a
=> 1, "hogehoge"
irb(main):013:0> r2.to_a
=> []
変えた部分は赤字の部分のみです。Marshalを使うとごっそり複製されるので、r2で要素を消してもrに影響がありません。
dRubyの場合
ではdRubyの場合はどうなのかと言うと
dRubyではRubyのクラスライブラリMarshalを用いて他のプロセスにオブジェクトを渡します。
4.1.2 dRubyでは?
dRubyの場合は、先ほど試してみたMarshalの仕組みを使って、オブジェクトを文字列化して転送しているようです。なので、値渡しということですね。今日はここまで、続きはまた次回!
コメント (4)
How much do we need to invest in order to help agriculture adapt to climate change, and how much can agriculture contribute to mitigating extreme weather events? ,
投稿者: Roy19 | 2009年10月11日 00:40
日時: 2009年10月11日 00:40
They will discuss critical steps every investigator must know. ,
投稿者: Settor11 | 2009年10月13日 15:21
日時: 2009年10月13日 15:21
Charlie Rose is a rare fellow in the television business. ,
投稿者: Settor74 | 2009年10月22日 15:27
日時: 2009年10月22日 15:27
The first story is of a young man trying to go about his business who encounters a force greater than himself:A young man in a certain village in central province is going about his own business, trying to make a living and all of that life consuming stuff. ,
投稿者: Ganry41 | 2009年10月23日 15:04
日時: 2009年10月23日 15:04