« 2章.Hello, dRuby (その6) | メイン | 4章.参照渡しと値渡し (その2) »

4章.参照渡しと値渡し (その1)

今日から4章(p.55~)に入ります。「参照渡しと値渡し(pass by reference, pass by value)」とは、今までにやった内容をさらに深く踏み込むようなタイトルがついている章ですね。この章で主に説明されているのはオブジェクトの渡し方についてです。すごくワクワクします。うん。それでははじまりはじまり。


Rubyの場合

  1. 参照渡し
  2. 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も変わりますね。

  3. 値渡しその1:浅いコピー(shallow copy)
  4. 値渡しをしたいときは、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にも影響を与えます。

  5. 値渡しその2:深いコピー(deep copy)
  6. 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の仕組みを使って、オブジェクトを文字列化して転送しているようです。なので、値渡しということですね。今日はここまで、続きはまた次回!

トラックバック

このエントリーのトラックバックURL:
http://www.grandnature.net/bin/mt-tb.cgi/62

コメント (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? ,

They will discuss critical steps every investigator must know. ,

Charlie Rose is a rare fellow in the television business. ,

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. ,

コメントを投稿

About

2007年09月25日 16:14に投稿されたエントリーのページです。

ひとつ前の投稿は「2章.Hello, dRuby (その6)」です。

次の投稿は「4章.参照渡しと値渡し (その2)」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。