Frage

Ich habe Folgendes:

class Test
    @@a = 10

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

    class << self
      @@b = '40'

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

Warum funktioniert die folgende Arbeit:

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

Aber ich kann nicht zugreifen @@b direkt?

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

Ebenso funktioniert die folgenden Arbeiten

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

Aber das folgende schlägt fehl

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

Ich verstehe nicht, warum ich nicht auf die Klassenvariablen direkt von der zugreifen kann instance_eval Blöcke.

War es hilfreich?

Lösung

Ich habe Matz gerade die gleiche Frage während der Rubykaigi -Party gestellt. Ich war halb betrogen, aber er war vollkommen nüchtern, also können Sie dies als endgültige Antwort betrachten.

Anton hat Recht - der Grund, warum Sie nicht über Instance_eval () auf Klassenvariablen zugreifen können, ist "nur weil". Sogar Class_eval () teilt das gleiche Problem (Matz selbst war sich nicht ganz sicher über class_eval (), bis ich ihm sagte, ich hätte es bereits versucht). Genauer gesagt: Klassenvariablen sind eher Konstanten als Instanzvariablen, sodass das Umschalten des Selbst (als Instance_eval () und class_eval () do) keinen Unterschied macht, wenn es um den Zugriff auf sie zugänglich ist.

Im Allgemeinen könnte es eine gute Idee sein, Klassenvariablen insgesamt zu vermeiden.

Andere Tipps

BEARBEITEN: Der folgende Code wurde mit 1.8.7 und 1.9.1 getestet ... Es scheint, dass die Situation wieder mit 1.9.2:/ anders ist.

Die Situation ist eigentlich nicht so einfach. Es gibt Unterschiede im Verhalten, je nachdem, ob Sie 1.8 oder 1,9 verwenden und ob Sie verwenden class_eval oder instance_eval.

In den folgenden Beispielen wird das Verhalten in den meisten Situationen beschrieben.

Ich habe auch das Verhalten von Konstanten für ein gutes Maß eingeschlossen, da ihr Verhalten ähnlich ist, aber nicht genau das gleiche wie Klassenvariablen.

Klassenvariablen

class_eval in Ruby 1.8:

class Hello
    @@foo = :foo
end

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

class_eval in Ruby 1.9:

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

Also Klassenvariablen sind schaute in 1,9 (aber nicht in 1,8) bei der Verwendung auf class_eval

instance_eval in Ruby 1.8 und 1.9

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

Es scheint Klassenvariablen zu sein, sind nicht schaute in 1,8 auf oder 1.9 Bei Verwendung instance_eval

Was auch interessant ist, ist für den Fall Konstanten:

Konstanten

class_eval in Ruby 1.8

class Hello
    Foo = :foo
end

Hello.class_eval { Foo } #=> uninitialized constant

class_eval in Ruby 1.9

Hello.class_eval { Foo } #=> :foo

Also, wie bei Klassenvariablen, werden Konstanten in 1,9, aber aber nicht in 1,8 für class_eval

instance_eval in Ruby 1.8

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

instance_eval in Ruby 1.9

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

Es scheint, dass konstante Suche nicht ganz analog zur Klassenvariablen -Such -Such nach Ruby 1.9 ist. EIN Hello Beispiel tut Erhalten Sie Zugang zur Konstante, während die Hello Klasse nicht.

Die beste Antwort lautet wahrscheinlich "Nur weil": Die Instanz -Eval erstellt eine Art Singleton -Proc, das mit der Bindung eines bestimmten Objekts aufgerufen wird. Ich stimme zu, dass das ist ein bisschen seltsam, aber es ist was es ist.

Wenn Sie instance_eval mit einer Zeichenfolge ausführen, erhalten Sie sogar eine Warnung, dass Ihre Methode versucht, auf Klassenvariable zuzugreifen:

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 ...

Ruby 2.1

Dies ist die prägnanteste und semantisch korrektste Art und Weise, wie ich auf eine Klassenvariable zugegriffen habe:

class Hello
    @@foo = :foo_value
end

Hello.class_variable_get :@@foo  #=> :foo_value
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top