Ruby オブジェクトをファイル(または文字列)に書き出したり、読み戻したりする機能を提供する
モジュールである。
Rubyのプログラムは、多数のオブジェクトがお互いにメッセージをやり取りしつつ動作する。
その無数のオブジェクトには寿命があり、生まれて、すぐに消滅してしまう(実際にはガーベージ・コレクタが動くまでカスが残り続けるわけだが)ウスバカゲロウのように儚いオブジェクトもあれば、いつまでもしぶとく生き残っているオブジェクトも存在するのである。
しかし、オブジェクトの寿命には限界がある。それは、『プログラムが起動してから終了するまで』なのである。プログラム本体の寿命より長生きするオブジェクトは存在しないし、もしプログラムが終了して後も、オブジェクトが死霊のごとく残存しているとすれば、これは俗に言うメモリリークが発生しているのであり、急いで原因を究明せねばならない。
だが、『そうか、オブジェクトの寿命はプログラムが起動して終了するまでか、なるほど。仕方ないなあ』で済ませるわけにはいかない。
例えば貴方がRubyでロールプレイングゲームの大作を作ったとする。不眠不休でプレイしたとしても、早くて100時間はかかろうかというものすごいものだ。だがこれには弱点があって、途中で止めることができないのである。なぜならオブジェクトの生存期間がプログラムの開始から終了までだから。
と、まあこういうゲームは誰も遊んでくれないわけであって、実行中の状態を保存してプログラムを終了し、プログラム再起動時には保存した状態を復元できなければならないのである。この状態の保存と復元を『永続性』と呼ぶ。
これが、手続き型や構造化プログラミング言語であれば、メインルーチンがグローバル変数かなんかの値を適当に編集してファイルに書き出しておけばよいわけであるが、オブジェクト指向プログラミング言語の場合、そう簡単にはいかない。
なぜならオブジェクト指向プログラミング言語で作成されたプログラムには、オブジェクトがうじゃうじゃと存在するわけだから、メインルーチンが全て面倒をみるわけにはいかないのだ。大体、PrivateやProtectedでデータを隠し持っている場合もあるわけだから、メインルーチンからは見えないのである。
従って、状態保存と復元はオブジェクト単位にできなければならないのだ。
このような背景があり、オブジェクト指向プログラミング言語には通常、オブジェクトの内容をバイト列に変換するシリアライズ(直列化)機能と、それをオブジェクトへ復元するデシリアライズ機能が存在するというわけだ。
では、サンプルコードを見てみよう。
001 | #犬クラスの定義
002 | class Dog
003 | def initialize(a=0, n="")
004 | @age=a
005 | @name=n
006 | end
007 | def say
008 | puts "私は#{@name}です。年齢は#{@age.to_i}歳です"
009 | end
010 | end
011 |
012 | pochi=Dog.new(1,"ポチ")
013 |
014 | clonePochi = Marshal.load(Marshal.dump(pochi))
015 |
016 | clonePochi.say
これは一体何をしているのかというと、Dogクラスのインスタンスpochiを生成し、Marshal機能を使って、クローン犬clonePochiを複製するという、神をも畏れぬ所業を行っているわけだ。
Marshal.dumpがシリアライズ、Marshal.loadがデシリアライズというわけだね。
『そんな回りくどいことしなくても、clonePochi=pochiでいいじゃないですか?』
確かにそうなのだが、それだとMarshalの解説にならないので…
最終更新:2009年03月14日 13:39