Pregunta

Tengo lo siguiente:

class Test
    @@a = 10

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

    class << self
      @@b = '40'

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

¿Por qué funciona el siguiente?

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

Pero no puedo acceder @@b ¿directamente?

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

Del mismo modo, lo siguiente funciona

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

Pero lo siguiente falla

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

No entiendo por qué no puedo acceder a las variables de clase directamente desde el instance_eval bloques.

¿Fue útil?

Solución

Solo le hice la misma pregunta a Matz durante la fiesta de Rubykaigi. Estaba a media derrota, pero él estaba perfectamente sobrio, por lo que puedes tomar esto como la respuesta definitiva.

Anton tiene razón: la razón por la que no puede acceder a las variables de clase a través de instance_eval () es "solo porque". Incluso class_eval () comparte el mismo problema (el propio Matz no estaba totalmente seguro de class_eval () hasta que le dije que ya lo había probado). Más específicamente: en cuanto al alcance, las variables de clase son más parecidas a las constantes que las variables de instancia, por lo que cambiar a sí mismo (como instance_eval () y class_eval () do) no hará ninguna diferencia cuando se trata de acceder a ellas.

En general, podría ser una buena idea evitar las variables de clase por completo.

Otros consejos

EDITAR: El siguiente código se probó con 1.8.7 y 1.9.1 ... Parece que la situación es diferente nuevamente con 1.9.2:/

La situación en realidad no es tan directa. Hay diferencias en el comportamiento dependiendo de si está utilizando 1.8 o 1.9 y si está utilizando class_eval o instance_eval.

Los ejemplos a continuación detallan el comportamiento en la mayoría de las situaciones.

También incluí el comportamiento de las constantes, en buena medida, ya que su comportamiento es similar a las variables de clase, pero no exactamente las mismas que las de clase.

Variables de clase

class_eval En Ruby 1.8:

class Hello
    @@foo = :foo
end

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

class_eval En Ruby 1.9:

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

Entonces variables de clase son miró hacia arriba en 1.9 (pero no en 1.8) cuando se usa class_eval

instance_eval En Ruby 1.8 y 1.9

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

Parece que las variables de clase son no miró hacia arriba en 1.8 o 1.9 Al usar instance_eval

Lo que también es interesante es el caso de constantes:

Constantes

class_eval En Ruby 1.8

class Hello
    Foo = :foo
end

Hello.class_eval { Foo } #=> uninitialized constant

class_eval En Ruby 1.9

Hello.class_eval { Foo } #=> :foo

Entonces, como con las variables de clase, las constantes se buscan en 1.9 pero pero no en 1.8 para class_eval

instance_eval En Ruby 1.8

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

instance_eval En Ruby 1.9

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

Parece que la búsqueda constante no es muy análoga a la variable de clase, busque Ruby 1.9. A Hello instancia lo hace Obtenga acceso a la constante mientras el Hello La clase no lo hace.

Bueno, probablemente la mejor respuesta es "solo porque": la instancia_eval en pocas palabras crea algún tipo de proceso singleton que se invoca con la vinculación de un objeto dado. Estoy de acuerdo en que suena un poco extraño, pero es lo que es.

Si ejecuta instance_eval con una cadena, incluso obtendrá una advertencia de que su método intenta acceder a la variable de clase:

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

Esta es la forma más concisa y semánticamente correcta que he encontrado para acceder a una variable de clase:

class Hello
    @@foo = :foo_value
end

Hello.class_variable_get :@@foo  #=> :foo_value
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top