どこかで働くプログラマーの日記

この日記のはてなブックマーク数

2007-02-03

[]Rubyでの参照渡し

Rubyで参照渡しを使うにはどうするのかというのが気になり、色々と調べてみました。

結論として、参照渡しを使うケースは主にひとつ以上の値をメソッドから取り出したいケースで、Rubyの場合は配列戻り値を返そうよっということみたいです。

引用元:
http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-list/613?593-819

rubyには変数の参照というものがないので,そういうことはできま
せん.変数の参照渡しがしたい時というのは大体において以下のよ
うな場合です.

  * オブジェクトのサイズが大きいとコピーのコストが大きい

    rubyオブジェクトは全部参照ですからオブジェクトサイズに
    かかわらず引数渡しのコストは同じです.

  * ひとつ以上の値をメソッドから取り出したい

    ruby配列を返すことで見掛け上複数の戻り値を返すことがで
    きます.

       a, b = foo(arg)

ただ、Rubyには変数の参照がないと書かれているのには?がともります。

例えば、

def test(hash_in)
	hash_in["c"] = 3
end

hash_out = {"a" => 1, "b" => 2}
test(hash_out)
p hash_out # 出力→{"a"=>1, "b"=>2, "c"=>3}

とすれば、関数内で格納した値が関数外でも格納されているので、これって参照渡しだよねって思うのです。

ただし、

def test(hash_in)
	hash_in = {"c" => 10, "d"=>11}
end

hash_out = {"a" => 1, "b" => 2}
test(hash_out)
p hash_out # 出力 → {"a"=>1, "b"=>2}

とすると、あれっやっぱり参照じゃないのかなっと訳がわからなくなるのです。

そこで、もう少し調べてみたところ、以下の記事を見つけました。

引用元:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/1534

rubyには値渡ししかなく引き数として与えられた変
数の値を変えても元の式の値は変わりません.ただし,オブジェク
トの参照が渡るので値に対して破壊的な操作は可能です.

ということで、Rubyでは引数は値渡ししかない。

ただし、値渡しでありながらもオブジェクトが渡っているので、そのオブジェクトに対する操作であれば関数外のオブジェクトに対しても影響を与えることができるということですね。サンプルプログラムの結果とも一致します。

ん?最後にまとめたつもりが、上の文書の繰り返しになってしまいました。。。

paellapaella 2007/02/04 22:22 むしろ、Rubyには参照渡ししかない、というように考えた方がシンプルだと思います。というのも、最後の引用元にある以下の記述:

> 仮引数に渡されたオブジェクトへの操作により実引数のオブジェクトも操作される
> 変数に代入されたオブジェクトへの操作によりもとののオブジェクトも操作される
> 仮引数への別のオブジェクトの代入は、実引数に影響しない。
> 変数に別のオブジェクトを代入してもは、もとのオブジェクトには影響しない。

という記述でピンと来たのですが、これは単に
 ・Rubyのオブジェクトは、特定の変数名に束縛されない
ということではないかなと。つまり、関数の引数としての変数(hash_in)であってもその先を指すオブジェクトは途中で変わってもいいわけです。最後の”hash_in={...}”は別のオブジェクトをそこで指すようになり、渡ってきたhash_outが指すオブジェクトは操作されていないままだから、外には伝わらない。逆に”hash_in[”c”]=3”のような破壊的なメソッドを使用した場合は渡ってきたオブジェクトが対象なので変化する。ということかなと。
例として次のようなプログラムを見ると分かりやすいと思います。
def test(arg1, arg2)
 arg1.delete(”b”)
 arg2.delete!(”b”)
end
a = ”abcabc”
b = ”abcabc”
test(a, b)
p a, b
この結果は、a #=> ”abcabc”のまま、b #=> ”acac”に変化します。
だから、むしろC的に言えばRubyは値渡しではなく参照渡ししかない。というふうに考えるべきでは、と思うのですが、いかがでしょう?

paellapaella 2007/02/04 23:06 ちょっと分かりにくい説明になってしまったので、自分ところのブログにも説明を書いておきました。変な文ですみません。

paellapaella 2007/02/06 00:00 ごめんなさい、全然違うことを書いていました。Rubyはやっぱり値渡しです。2/4の日記ではなく、2/5の方を見てください。

恥ずかしい・・・

ioxiox 2007/02/06 00:44 コメントありがとうございます。
Rubyはやはり値渡しなんですねぇ。
2/5のまとめの記事、参考になりますm(_ _)m

shunsukshunsuk 2007/11/07 14:41 オブジェクトへの参照(ポインタ)がコピーされて渡される。と考えると良いと思います。

ioxiox 2007/11/07 18:33 コメントありがとうございます。
そうですね。そもそもオブジェクトが参照ということで理解しています。
それが、値渡しされるので呼び出される側で値を変えると呼び出し側の値も変わると。。。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証