2018-05-15

Ruby は参照渡し

Ruby は参照がないといった風説があるらしいので、メモ。

〜〜〜
Ruby にはポインタと呼ばれる構文がありませんが、参照がないというのは逆です。むしろ全部ポインタと思ったほうが誤りから遠いでしょう。
なぜかというと、万物がオブジェクトであり参照だからです。

String 型の値を変数 a に保持し、それを b に代入したとき、単なる参照の写しが作られ、b の指示先(値)を破壊すると、 a も破壊される例。

        a = "foo"
        b = a
        b[2] = 'x'
        a                => "fox"

Array 型の値を変数 a に保持し、それを b に代入したとき、単なる参照の写しが作られ、b の指示先(値)を破壊すると、 a も破壊される例。

        a = [1, 3.14, "foo"]
        b = a
        b[2] = 'x'
        a                => [1, 3.14, "x"]

メソッドの引数も、 arg = value という形の代入文と同様に、値ではなく参照が渡されます。

        def action!(arg)
          arg[2] = 'x'
        end
        a = [1, 3.14, "foo"]
        action!(a)
        a                => [1, 3.14, "x"]

数値たとえば 1 や 3.14 なども、参照を意識しなくてもプログラムできますが、参照と矛盾する動きをするわけではありません。(実装上ポインタを使わない高速化はされているけど)

        a = 1
        a += 3.14

であれば、最初に a に入っていた 1 を指示するオブジェクトは、次の += 代入文で参照を失って破棄されます。

発展

レシーバーも引数とおなじように破壊されます。String 型のメソッドなどの、名前が ! で終わるメソッドは破壊的といって、レシーバーの値が破壊されます。

        a = "foo"
        a.sub!(/f/, 'F')                => "Foo"        を返すとともに、a が破壊される
        a                        => "Foo"

破壊的メソッドがあるばあいは非破壊的メソッドが用意されています。

        a = "foo"
        a.sub(/f/, 'F')                => "Foo"        を返すが、a は破壊されない
        a                        => "foo"

0 件のコメント:

コメントを投稿