Rubyコーディングあれこれ (初めての方むけ: オブジェクトリンクの断ち切り方)
本地震の予測マップ・プログラムはRubyで書かれていますが、以前から初めての方むけにコーディングテクのようなモノをまとめておければ、と考えていました。 そこで思い付くままにまとめてみよう、と考えております。
今回は、オブジェクトリンクの断ち切り方です。 (短くまとめます)
Rubyはオブジェクト指向なので、データを変更するとさかのぼって変更されてしまいます。 それ困るんですけど、という場合の断ち切り方です。 これは極めて重要で、もっと早く書くべきでした(済みません)。
どういう場合に困るのかと言うと、データをライブラリとして持つ場合です。 データをライブラリとして保有して使われる状況に応じて(インスタンス化される状況に応じて)変更したい、というケースは多い訳で、この場合にデータを変更すると元のライブラリまでさかのぼって変更されてしまいます。
これを断ち切るには、まず素材を String で持つのではなく、すべて Symbol で持ちます。
Symbolデータ -> String化して変更する -> インスタンス化されたデータとして使う、です。
library = :"data color is -item" # "data color is -item" をライブラリとして Symbol で持ち、
# ^^^^^ 必要に応じて -item を確定した色に変更するライブラリとします。
change = "blue" # 飛び込んできた変更が "blue" であった場合は、
data = "#{library}".sub(/-item$/,"#{change}") # (1)
# ^^^ -item を change で示される内容に書き換えて data に格納。
:"data color is -item" は "data color is -item".to_sym と同じですが、この方が早い。 "#{library}" も library.to_s と同じですが、この方が早い。
"#{change}" は、この場合は "blue" と書くのと同じです。 上記(1)は
data = "#{library}".sub(/-item$/,"blue") と同じですが(1)の方が change に変更分が格納されているのでライブラリを書き換えているイメージがあり、そうしただけです。
#{} 表現はむちゃくちゃ使います。
上で述べたように、some_thing.to_s ではなく "#{some_thing}"、 some_thing.to_sym ではなく :"#{some_thing}"。
正規表現にも使えて:
specified = "-item"
compare = /#{specified}$/ # specified で示された内容と$ (これについては別途書きます)。
change = "blue"
data_array.each_with_index do |i,x|
if i =~ compare # #{} は毎回評価されるので必ず loop の外に出せる場合は出す
data_array[x] = i.sub(compare,change) # このケースでは i に String を想定
end # この場合は -item をすべて "blue" に書き換えるケースです
end
メッセージの埋め込みに使えて(これは極めて便利です、これが #{} 本来の使い方):
err_message(data_size, :"Error_1234") # エラーをcallする側
def err_message(data_size,msg) # data_size は整数で構わない
p "#{msg}: strange data size detacted -> #{data_size}" # 何でもプリントできる
end # メッセージの埋め込みは本当に便利なので、色々試される事をおすすめします。
話を戻して、オブジェクトリンクの断ち切り方ですが、何でも Symbol で持てば大丈夫かと言うと、そうでもありません。 Array の中身を Symbol で持てばリンクは断ち切れるのか、というとシッカリとリンクしています。
Array の場合は Hash を作り、 Array を Hash のアイテムとして入れてやらないと変更されてしまいます。
そして使う場合は:
data_array = Array.new(hash[key]) # 新規なArrayとして元とのリンクを断ち切る
常に新規なArrayを引っ張ってくる、それから変更、という操作が必要です。
結論:
データはすべてアイテムを Symbol化した Hash で持つ。 Array も内容を Symbol化させて Hash で持つ。 ライブラリのみならず通常のデータもこの方が安全。
大丈夫だと思う場合のみ String のまま Array で持ちます。 外部ファイルから中身をロードした時は String になっているので、これを Symbol に変更するだけでも時間がかかります。 一回しか変更しない事が分かっている場合はここまでやらなくて大丈夫です。
以上です。