Rubyのシンボルテーブルの設計と実装
-
14-11-2019 - |
質問
Rubyで字句解析装置を構築しており、シンボルテーブルのシンボルの収集と保存を開始しようとしています。シンボルの設計に関する主な質問とそれが静的テーブルであるべきかどうか(つまり、すべてのデータがクラスレベルで保持されることを意味)、またはインスタンスにインスタンスにあるべきかどうかについての主な質問。
オプション1:クラスレベルデータ構造
.
require 'SymbolTableEntry.rb'
class SymbolTable
@sym_table = Array.new(500)
def initialize()
end
def SymbolTable.add(element, index)
@sym_table[index] = element if element.is_a? SymbolTableEntry
end
def SymbolTable.to_s
pp @sym_table
end
end
この方式では、SymbolTableクラスには「静的」機能がある種の「静的」機能を持ちます。つまり、記号テーブルのインスタンスを作成しないことで、存在する唯一のオブジェクトはクラスレベル1です。
(ここで定義していなくても、SymbolTableEntry
が有効なオブジェクトであるとします)
ex:
.
irb(main):002:0> require 'SymbolTable.rb'
=> true
irb(main):003:0> ste = SymbolTableEntry.new
=> #<SymbolTableEntry:0x7ef36884>
irb(main):004:0> SymbolTable.add(ste, 10)
=> #<SymbolTableEntry:0x7ef36884>
irb(main):005:0> SymbolTable.to_s
[nil,
nil,
nil,
nil,
nil,
nil,
nil,
nil,
nil,
nil,
#<SymbolTableEntry:0x7ef36884>]
=> nil
オプション2:インスタンスレベルデータ構造
.
require 'rubygems'
require 'backports'
require 'SymbolTableEntry.rb'
class SymbolTable
def initialize()
@sym_table = Array.new(10)
end
def add(element, index)
@sym_table[index] = element if element.is_a? SymbolTableEntry
end
def to_s
pp @sym_table
end
end
この方式では、シンボルテーブルに値を追加するために、実際にシンボルテーブルクラスのインスタンスをインスタンス化する必要があります。
.
irb(main):001:0> require 'SymbolTable.rb'
=> true
irb(main):002:0> st = SymbolTable.new
=> #<SymbolTable:0x7eeb6c9c @sym_table=[nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil]>
irb(main):003:0> ste=SymbolTableEntry.new
=> #<SymbolTableEntry:0x7eeb4d5c>
irb(main):004:0> st.add(ste,10)
=> #<SymbolTableEntry:0x7eeb4d5c>
irb(main):007:0> st.to_s
[nil,
nil,
nil,
nil,
nil,
nil,
nil,
nil,
nil,
nil,
#<SymbolTableEntry:0x7eeb4d5c>]
=> nil
私はあなたが一般的なRubyコードについてのコメントも、あなたが使用するか、または使用するのを好むすべての入力を聞きたいと思います。
ありがとう
解決
クラス変数を介してインスタンス変数を渡します。クラス変数を使用したクラス以外の理由がない場合は、単位テストの痛みのもう少しの痛みです。
インスタンス変数を使用してもまだそれらをルールするための1つのシンボルテーブルがあります。1つの方法は、シンボルテーブルをグローバル変数に割り当てることです。
$symbol_table = SymbolTable.new
.
一部の言語では、グローバル変数を使用するクラスはテストするのが困難です。Rubyでは、デックのタイピングを使用すると、テスト中のオブジェクトを実行する前にモックオブジェクトをグローバル変数に割り当てることができます。
または、シングルトンパターンを使用することができます。Rubyはこの簡単にするための図書館が付属しています:
require 'singleton'
class SymbolTable
include Singleton
...
end
.
SymbolTableの1台と唯一のインスタンスを取得するには、必要に応じて作成しました。
SymbolTable.instance
. 他のヒント
インスタンス変数を使用します。テスト処理の理由から、(少なくともだけでなく)はありません。むしろだから
- すべての解析プロセスはそれ自身のシンボルテーブルを生成しますので、一度に複数の時間に1つ以上あることがあります。
- シンボルテーブルは、解析プロセスがアンダー状態の場合にのみ必要です
- クラス変数はスレッドの安全を達成するために同期をする必要性を導入します - すべての解析プロセスはそれ自身のシンボルのセットに完全によく生きることができます
歓声
ロバート
Robert and Wayneによって与えられた数の答えへの迅速な説明は、どちらもクラス変数。
元の質問は、クラス変数をまったく使用することを提案しませんが、クラスインスタンス変数を使用することについて尋ねます。提示された最初の選択ハンターは、第2のオプションがシンボルのインスタンスに格納されている状態でより一般的なクラス/インスタンスフレームワークを使用している間に、クラスオブジェクト自体をシンボルテーブルの単一のインスタンス(クラスインスタンス変数に格納されています)を使用しました。表
Rubyのクラス変数はクラスインスタンス変数と同じものではなく、一般的には避けられるべきです。