23

私は次のものを持っています:

class Test
    @@a = 10

    def show_a()
        puts "a: #{@@a}"
    end

    class << self
      @@b = '40'

      def show_b
        puts "b: #{@@b}"
    end
  end
end

以下が機能する理由:

Test.instance_eval{show_b}
b: 40
=> nil

しかし、私は@@b直接アクセスできませんか?

Test.instance_eval{ @@b }
NameError: uninitialized class variable @@b in Object

同様に、次の作品

t = Test.new
t.instance_eval{show_a}
a: 10
=> nil

しかし、以下は失敗します

t.instance_eval{ @@a }
NameError: uninitialized class variable @@a in Object

instance_evalブロックからクラス変数に直接アクセスできない理由がわかりません。

4

4 に答える 4

18

RubyKaigi パーティーでマッツに同じ質問をしました。私は酔っ払っていましたが、彼は完全に冷静だったので、これを決定的な答えとして受け取ることができます.

Anton の言うとおりです。instance_eval() を介してクラス変数にアクセスできない理由は、「ただの理由」です。class_eval() でさえ同じ問題を共有しています (Matz 自身は、class_eval() について私が既に試したことがあると伝えるまで、完全には確信が持てませんでした)。より具体的には、クラス変数はインスタンス変数よりも定数に似ているため、(instance_eval() と class_eval() が行うように) self を切り替えても、それらにアクセスする際に違いはありません。

一般に、クラス変数を完全に回避することをお勧めします。

于 2010-08-27T12:38:20.240 に答える
16

編集:以下のコードは 1.8.7 と 1.9.1 でテストされています... 1.9.2 では状況が異なるようです:/

状況は実際にはそれほど単純ではありません。class_eval1.8 と 1.9 のどちらを使用しているか、またはを使用しているかによって、動作に違いがありますinstance_eval

以下の例では、ほとんどの状況での動作について詳しく説明しています。

また、定数の動作はクラス変数と似ていますが、まったく同じではないため、適切な測定のために含めました。

クラス変数

class_evalルビー1.8で:

class Hello
    @@foo = :foo
end

Hello.class_eval { @@foo } #=> uninitialized class variable

class_evalRuby 1.9 で:

Hello.class_eval { @@foo } #=> :foo

そのため、クラス変数1.9 で検索されます (1.8 では検索されません)。class_eval

instance_evalRuby 1.8および1.9で

Hello.instance_eval { @@foo } #=> uninitialized class variable
Hello.new.instance_eval { @@foo } #=> uninitialized class variable

使用時にクラス変数が1.8または1.9で検索されないようですinstance_eval

また興味深いのは、定数の場合です。

定数

class_evalルビー1.8で

class Hello
    Foo = :foo
end

Hello.class_eval { Foo } #=> uninitialized constant

class_evalルビー1.9で

Hello.class_eval { Foo } #=> :foo

したがって、クラス変数と同様に、定数は 1.9 では検索されますが、1.8 では検索されません。class_eval

instance_evalルビー1.8で

Hello.instance_eval { Foo } #=> uninitialized constant
Hello.new.instance_eval { Foo } #=> uninitialized constant

instance_evalルビー1.9で

Hello.instance_eval { Foo } #=> uninitialized constant
Hello.new.instance_eval { Foo } #=> :foo

定数ルックアップは、Ruby 1.9 のクラス変数ルックアップとあまり似ていないようです。Helloインスタンス定数にアクセスできますが、クラスHelloはアクセスできません。

于 2010-08-28T11:19:18.047 に答える
5

まあ、おそらく最良の答えは「ただの理由」です。一言で言えば、instance_eval は、特定のオブジェクトのバインディングで呼び出されるある種のシングルトン proc を作成します。少し奇妙に聞こえることに同意しますが、それが何であるかです。

文字列を指定して instance_eval を実行すると、メソッドがクラス変数にアクセスしようとしているという警告が表示されます。

irb(main):038:0> Test.new.instance_eval "@@a"
(eval):1: warning: class variable access from toplevel singleton method
NameError: (eval):1:in `irb_binding': uninitialized class variable ...
于 2010-08-12T08:10:29.127 に答える
4

ルビー2.1

これは、クラス変数にアクセスするために私が見つけた最も簡潔で意味的に正しい方法です。

class Hello
    @@foo = :foo_value
end

Hello.class_variable_get :@@foo  #=> :foo_value
于 2014-03-14T18:01:58.017 に答える