Domanda

Ho quanto segue:

class Test
    @@a = 10

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

    class << self
      @@b = '40'

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

Perché seguire il lavoro:

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

Ma non posso accedervi @@b direttamente?

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

Allo stesso modo, il seguente funziona

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

Ma il seguente fallisce

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

Non capisco perché non riesco ad accedere alle variabili di classe direttamente da instance_eval blocchi.

È stato utile?

Soluzione

Ho appena fatto la stessa domanda a Matz durante la festa di Rubykaigi. Ero mezzo ubriaco, ma era perfettamente sobrio, quindi puoi prendere questo come risposta definitiva.

Anton ha ragione: il motivo per cui non è possibile accedere alle variabili di classe tramite Instance_eval () è "solo perché". Anche Class_eval () condivide lo stesso problema (lo stesso Matz non era totalmente sicuro di Class_eval () fino a quando non gli ho detto che l'avrei già provato). Più specificamente: per quanto riguarda l'ambito, le variabili di classe sono più simili a costanti che variabili di istanza, quindi il passaggio di sé (come fanno istanza_eval () e class_eval ()) non farà alcuna differenza quando si tratta di accedervi.

In generale, potrebbe essere una buona idea evitare del tutto le variabili di classe.

Altri suggerimenti

MODIFICARE: Il codice sotto è stato testato con 1.8.7 e 1.9.1 ... sembra che la situazione sia di nuovo diversa con 1.9.2:/

La situazione in realtà non è così semplice. Ci sono differenze nel comportamento a seconda che tu stia usando 1.8 o 1.9 e se stai usando class_eval o instance_eval.

Gli esempi di seguito descrivono il comportamento nella maggior parte delle situazioni.

Ho anche incluso il comportamento delle costanti, per una buona misura, poiché il loro comportamento è simile, ma non esattamente lo stesso delle variabili di classe.

Variabili di classe

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

Quindi variabili di classe sono alzato lo sguardo in 1.9 (ma non in 1.8) quando si usa class_eval

instance_eval In Ruby 1.8 e 1.9

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

Sembra che le variabili di classe siano non alzato lo sguardo in 1.8 o 1.9 Quando si utilizza instance_eval

Ciò che è anche interessante è il caso costanti:

Costanti

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

Quindi, come per le variabili di classe, le costanti sono cercate in 1.9 ma non in 1.8 per 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

Sembra che la ricerca costante non sia abbastanza analoga alla variabile di classe Cerca Ruby 1.9. UN Hello esempio fa ottenere l'accesso alla costante mentre il Hello la classe no.

Bene, probabilmente la risposta migliore è "solo perché": l'istanza_eval in poche parole crea una sorta di procleton Proc che è invocato con il legame di un determinato oggetto. Sono d'accordo che sia un po 'strano, ma è quello che è.

Se esegui Instance_eval con una stringa, otterrai anche un avvertimento che il tuo metodo cerca di accedere alla variabile di classe:

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

Questo è il modo più conciso e semanticamente corretto che ho trovato per accedere a una variabile di classe:

class Hello
    @@foo = :foo_value
end

Hello.class_variable_get :@@foo  #=> :foo_value
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top