変数とオブジェクトと参照

 2012-11-18
RGSSの基本中の基本。
これを知らずしてスクリプトが扱えるか!!

ということで、変数とオブジェクトの関係をおさらいしてみましょう。

「変数」とは、オブジェクトにつけた名前のことです。
この名前をつける行為を「代入」といいます。
「オブジェクト」とは、データ(値)と処理(メソッド)をまとめたものです。
SS121114830436.png
オブジェクト自体には名前がないので、変数を使用してオブジェクトを指定します。
Ruby は、すべての値がオブジェクトのため、変数に代入されるのは、
値(オブジェクト)自体ではなく、オブジェクトの参照です。
「参照」とは、オブジェクトの位置情報や管理番号のようなものとお考えください。
a = "Hello"         # 文字列に a という名前をつける
b = a # 変数 a のオブジェクトに b という名前をつける
b.push(", RGSS!")
p a, b # どちらも "Hello, RGSS!"
のような処理でも、オブジェクトが複製されることはなく、
右辺の変数が保持している参照をコピーして、左辺の変数に代入します。
ですので、変数 a と b は、どちらも同じオブジェクトを参照することになります。


変数と参照が理解できていれば、メソッドの引数でも戸惑うことはありません。
Ruby の引数は、すべて値渡しです。
変数には、オブジェクトの参照が格納されているので、当然、引数にも参照が渡されます。
つまり、参照の値渡しということになります。
ary = [1, 2]
def add3(arg)
arg[2] = 3
end
add3(ary)
p ary # => [1, 2, 3]
オブジェクトの値が変更されるのは、配列の参照を渡しているからで参照渡しだからではありません。
a = 123
def zero(a)
a = 0
end
zero(a)
p a # => 123
このように参照渡しの機能はありません。


最後にオブジェクトのコピーについても触れておこうと思います。
オブジェクトの複製方法は、大きく分けて2種類があります。
浅いコピーと呼ばれる clone と dup 、深いコピーと呼ばれる Marshal を使った方法です。
clone と dup の違いは、マニュアルを見ていただくとして、
浅いコピーと深いコピーの違いを説明したいと思います。

まず、浅いコピーは、メソッドを実行したオブジェトのみの複製をします。
この場合は、変数 a のオブジェクトのみコピーされます。
つまり、配列オブジェクトだけですね。
配列から参照される要素のオブジェクトまではコピーされないので、
文字列の値を変更すれば、当然 a と b の配列から参照されている文字列は同じものなので、
両方が変更されます。
配列オブジェクトはコピーされて別のオブジェクトとなっているので、
配列に変更を加えた場合は、片方のみに適用されます。
a = ["A", "B"]
b = a.clone
b[1].concat("C")
b.push("D")
p a # => ["A", "BC"]
p b # => ["A", "BC", "D"]

配列の要素までコピーしたい場合は、深いコピーを行う必要があります。
オブジェクトが参照しているものすべてを複製すればいいわけですが、
これだと、独自クラスの場合などにコピー用のメソッドを用意しなくてはなりません。
今回の例では、簡単ですが、参照しているオブジェクトによっては複雑になり面倒です。
a = ["A", "B"]
b = a.map {|obj| obj.clone }
b[1].concat("C")
b.push("D")
p a # => ["A", "B"]
p b # => ["A", "BC", "D"]

そこで、Marshal を使用します。これはオブジェクトを文字列に変換するものです。
その過程で新しいオブジェクトが作成されるので、深いコピーを行う際に使用されています。
Marshal.dump で文字列に変換し、Marshal.load で復元します。
a = ["A", "B"]
b = Marshal.load(Marshal.dump(a))
b[1].concat("C")
b.push("D")
p a # => ["A", "B"]
p b # => ["A", "BC", "D"]


以上で、変数とオブジェクトの関係の説明は終わりです。
浅いコピー、深いコピーは、オブジェクトによっては適用できない場合もあります。
その辺の説明は省かせていただきましたので、マニュアルなどで確認してください。

オブジェクトが同一のものであるかは、IDを確認することでわかります。
a = "A"
p a.object_id # 6785920
p a.__id__ # 6785920
b = a
p b.object_id # 6785920
c = b.clone
p c.object_id # 6785810
コメント




 

 ※ コメント内にURLを含めるには、バッククォート(`)をURLの直前に付け加えてください。


管理人のみ閲覧許可 [?]

トラックバック
トラックバックURL:
http://cacaosoft.blog42.fc2.com/tb.php/663-a54c3c5e
≪ トップページへこのページの先頭へ  ≫
カレンダー
06 << 2017/07 >> 08
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -

カテゴリー
最近の記事
最近のコメント
03/16 お返事
01/21 お返事
11/30 z座標
11/20 z座標
08/03 お返事

タグクラウド

リンク