2

Rubyで、クラスのコンテンツをで定義するとclass_exec、予期しない結果が発生します。に送信されたブロックでクラス変数を定義すると、呼び出されているクラスではなくclass_exec、クラス変数が定義されます。Objectclass_exec

class X; end
X.class_exec do
  @@inner_value = "123"
  def inner_value
    @@inner_value
  end
  def inner_value=(arg)
    @@inner_value = arg
  end
end

obj1 = X.new
puts obj1.inner_value
puts @@inner_value
puts Object.class_variables

生産:

123
123
@@inner_value

これは、以下を使用する場合は発生しませんclass_eval

X.class_eval(<<-RUBY)
  @@inner_value = "123"
  def inner_value
    @@inner_value
  end
  def inner_value=(arg)
    @@inner_value = arg
  end
RUBY

obj1 = X.new
puts obj1.inner_value
puts @@inner_value
puts Object.class_variables

生産:

123

およびエラー:

uninitialized class variable @@inner_value in Object (NameError)

class_evalを使用した結果は、どちらの場合も発生すると予想される結果です。MRI1.8.7とMRI1.9.3の両方でこれを試しましたが、WindowsXPで同じ結果が得られました。

これは予想される動作ですか?もしそうなら、なぜですか?そうでない場合、バグ?

4

1 に答える 1

2

クラス変数は、コンパイル時に宣言されたクラスにバインドされます。に渡されるブロックは、にclass_exec渡される前にコンパイルされるclass_execため、クラス変数はにバインドされObjectます。

私はあなたのclass_execがオブジェクトにあるトップレベルにあると思います、それで彼らはそこに行きます。実証するために:

public

class Object
    @@x = "ribbit"
end

def foo
    puts "test: #{@@x}"
end

x = Object.new
x.foo

これが、モジュールでクラス変数を使用する場合、(含まれているメソッドを介して)そのモジュールを含むすべてのクラスが同じクラス変数を参照する理由です。クラス変数はモジュールにバインドされています。これを実行する場合:

class WithClassVars
    def self.classvars
        @classvars ||= {}
    end

    def classvars
        self.class.classvars
    end
end

class A < WithClassVars;end
class B < WithClassVars;end

a = A.new
b = B.new
a.classvars[:a] = 1
b.classvars[:a] = 2

puts a.classvars
puts b.classvars

aとbは同じデータになります。

コードを文字列としてに渡すとclass_eval、文字列はでコンパイルされる class_evalため、適切なクラスにあることを確認できます。

したがって、クラスごとのデータを保存する場合は、class_evalを使用するか、何らかのメカニズムを使用してクラスのインスタンス変数を使用する必要があります。言う:

class WithClassVars
    def self.classvars
        @classvars ||= {}
    end

    def classvars
        self.class.classvars
    end
end

class A < WithClassVars;end
class B < WithClassVars;end

a = A.new
b = B.new
a.classvars[:a] = 1
b.classvars[:a] = 2

puts a.classvars
puts b.classvars
于 2012-04-11T18:11:15.033 に答える