2

私は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 クラスは一種の「静的」機能を備えています。つまり、SymbolTable のインスタンスを実際に作成するのではなく、存在する唯一のオブジェクトはクラス レベルのオブジェクトです。

SymbolTableEntry(ここでは定義していませんが、有効なオブジェクトであると仮定します)

元:

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

このスキームでは、シンボル テーブルに値を追加するために、SymbolTable クラスのインスタンスを実際にインスタンス化する必要があります。

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 コードに関するコメントをお待ちしております。

ありがとう

4

3 に答える 3

1

クラス変数を使用するクラスが単体テストを行うのが少し面倒であるという理由以外に理由がない場合は、クラス変数よりもインスタンス変数を優先してください。

インスタンス変数を使用しても、1 つのシンボル テーブルですべてを支配することができます。1 つの方法は、シンボル テーブルをグローバル変数に割り当てることです。

$symbol_table = SymbolTable.new

一部の言語では、グローバル変数を使用するクラスのテストが困難です。Ruby では、ダック タイピングを使用すると、テスト対象のオブジェクトを実行する前にモック オブジェクトをグローバル変数に割り当てることができるため、それほど悪くはありません。

または、シングルトン パターンを使用できます。Ruby には、これを簡単にするためのライブラリが付属しています。

require 'singleton'
class SymbolTable
  include Singleton
  ...
end

SymbolTable の唯一無二のインスタンスを取得するには、必要に応じて作成します。

SymbolTable.instance
于 2012-01-26T05:20:09.730 に答える
1

インスタンス変数を使用します。しかし、テスト処理の理由からではありません (少なくともそれだけではありません)。むしろ

  • すべての解析プロセスは独自のシンボル テーブルを生成するため、一度に複数のシンボル テーブルを作成することができます。
  • シンボル テーブルは、解析プロセスが進行中の場合にのみ必要です。
  • クラス変数は、スレッドセーフを達成するために同期を行う必要性を導入します - すべての解析プロセスは独自のシンボルセットで完全にうまく機能しますが

乾杯

ロバート

于 2012-01-26T08:02:12.410 に答える
0

ロバートとウェインによって与えられたいくつかの回答を簡単に説明します。どちらもクラス変数について言及しています。

元の質問では、クラス変数の使用はまったく提案されていませんが、クラス インスタンス変数の使用について質問されています。Hunter が提示した最初の選択肢では、クラス オブジェクト自体をシンボル テーブルの単一のインスタンスとして使用しました (状態はクラス インスタンス変数に格納されます)。テーブル。

Ruby のクラス変数は、クラスのインスタンス変数と同じではなく、一般的に避けるべきです。

于 2012-01-26T22:14:39.600 に答える