Rubyハッシュキーとしてのオブジェクト
Ruby 3x3の取り組みをフォローしている場合は、おそらくOptcarrotについて聞いたことがあるでしょう。これは純粋なRubyで書かれたNESエミュレーターです。
私は最近、Optcarrotのソースを調べていましたが、興味深い詳細が1つ浮き彫りになりました。これは、見過ごされがちですが非常に便利なRubyのハッシュの機能を多用します。これは、任意のオブジェクトをハッシュキーとして使用する機能です。
コンテキスト:NESメモリマッピング
高レベルのプログラマーとして、私たちはメモリをRAMと考える傾向があります。しかし、下位レベルでは、「メモリ」には他にも多くの用途があります。
「メモリ」の読み取りと書き込みは、NESのCPUがGPU、コントロールパッド、およびカートリッジ上の特別な電子機器と通信する方法です。使用するアドレスに応じて、write_to_memory
メソッド呼び出しは、ジョイスティックをリセットしたり、VRAMを交換したり、サウンドを再生したりする可能性があります。
これをRubyでどのように実装しますか?
Optcarrotは、2つのMethod
を保存することでそれを行います 65536アドレスごとのオブジェクト。 1つはゲッターで、もう1つはセッターです。次のようになります:
@getter_methods[0x0001] = @ram.method(:[])
@setter_methods[0x0001] = @ram.method(:[]=)
問題:オブジェクトの重複
Object#method
の使用に関する問題 このように、それは多くの個別のMethod
を作成するということです 同一のオブジェクト。
これは、object_id
を見るとわかります。 :
> a = []
> a.method(:[]=).object_id
=> 70142391223600
> a.method(:[]=).object_id
=> 70142391912420
2つのMethod
オブジェクトのobject_id
は異なります 値なので、同じことをしていても、それらは異なるオブジェクトです。
通常、いくつかの余分なMethod
は気にしないかもしれません オブジェクトですが、この場合は何千ものオブジェクトを扱っています。
解決策:ハッシュによるメモ化
Optcarrotは、重複するMethod
を回避します 見落としがちな非常に単純なトリックでのオブジェクトの問題。
ハッシュを使用してメモ化し、重複排除します。以下の簡略化されたコードは、この手法を示しています。
def initialize
@setter_methods = []
@setter_cache = {}
...
end
def add_setter(address, setter)
# Doesn't store duplicates
@setter_cache[setter] ||= setter
# Use the deduped version
@setter_methods[address] = @setter_cache[setter]
end
これは、Hash
が機能するために機能します キーとしてどのようなオブジェクトを指定してもかまいません。
これが紛らわしい場合は、文字列を使用してIRBで試してください:
> cache = {}
> cache["foo"] ||= "bar"
=> "bar"
cache["foo"] ||= "baz"
=> "bar"
ここで、Rubyでは、文字列はクラスString
のインスタンスであると考えてください。 。 Rubyが文字列をハッシュキーとして使用するために使用したメカニズムは、基本的にMethod
を格納するために使用したメカニズムと同じです。 物体。
文字列以外のオブジェクトをハッシュキーとして使用すると、Hash
はどのように行われるのかという疑問が生じます。 2つのオブジェクトが等しいかどうか知っていますか?
答えは、Object#hash
を使用しているということです 方法。このメソッドはオブジェクトを調べ、再帰的にハッシュを生成します。次のようになります:
> a.method(:[]=).hash
=> 929915641391564853
同一のオブジェクトは同一のハッシュ値を生成するため、同等性のテストとして使用できます。
a.hash == b.hash
興味深いことに、これはeql?
で使用されているのと同じアプローチです。 方法:
a.eql?(b)
これはMethod
で機能します この例のオブジェクト:
> a.method(:[]=).hash == a.method(:[]=).hash
=> true
Ruby Web開発パターンに慣れてきたので、optcarrotソースを見て、リアルタイムの非Webアプリがさまざまなパターンをどのように使用しているかを確認するのは非常に興味深いことでした。 Webアプリでは、65536要素の配列を作成することはないと思いますが、ここでは、「デスクトップ」アプリのセットアップの一部として、それは非常に理にかなっています。
ご質問やご意見がございましたら、[email protected]またはTwitterの@StarrHorneまでご連絡ください。
-
Ruby内部:Rubyオブジェクトのメモリレイアウトの調査
Ruby内部のクイックツアーをご希望ですか? その後、あなたは御馳走になります。 なぜなら … Rubyオブジェクトがメモリ内にどのように配置されるか、そして内部データ構造を操作していくつかのクールなことを行う方法を一緒に探求します。 シートベルトを締めて、Rubyインタープリターの奥深くへの旅の準備をしてください! アレイのメモリレイアウト 配列を作成するとき、Rubyはそれをシステムメモリと少しのメタデータでバックアップする必要があります。 メタデータに含まれるもの : 配列サイズ(アイテム数) アレイ容量 クラス オブジェクトのステータス(凍結されているかどうか) データが
-
Ruby Freezeメソッド–オブジェクトの可変性を理解する
オブジェクトが可変であるとはどういう意味ですか? 派手な言葉で混乱させないでください。「可変性 」は、オブジェクトの内部状態を変更できることを意味します。これは、凍結されたオブジェクトを除く、すべてのオブジェクトのデフォルトです。 、または特別なオブジェクトのリストの一部であるもの。 つまり、Rubyのすべてのオブジェクトが変更可能というわけではありません! 例 : 数字や記号、さらにはtrueには意味がありません またはfalse (オブジェクトでもあります)変更します。 数字の1は常に1になります。 ただし、他のオブジェクト、特に配列オブジェクトやハッシュオブジェクトなどのデー