2010-01-18 23 views
22

Las cosas de clase de Ruby me están dando dolor de cabeza. Entiendo que dieron este ...Variables de clase Ruby

class Foo 
    @var = 'bar' 
end 

... que @var es una variable en la instancia de la clase creada.

Pero, ¿cómo creo una variable de clase invalidable de subclase?

Aquí es un ejemplo de lo que haría en Python:

class Fish: 
var = 'fish' 
def v(self): 
    return self.var 

class Trout(Fish): 
    var = 'trout' 

class Salmon(Fish): 
    var = 'salmon' 

print Trout().v() 
print Salmon().v() 

que da salida:

trout 
salmon 

¿Cómo puedo hacer lo mismo en el rubí?

+1

no deben' t que sea @@ var en el primer bloque de código? – Jean

+0

Estoy leyendo "The Well-Grounded Rubyist" (http://manning.com/black2/) por David Black. Hace un gran trabajo al explicar todos los matices en esta área –

+1

Jean: No. Si utilicé '@@ var', las subclases anularían las clases principales. Ver el enlace de hobodave. Específicamente cómo '2' se anula en el ejemplo. –

Respuesta

8

@var mencionado anteriormente se denomina variable de instancia de clase , que es diferente de las variables de instancia ... leer la respuesta here para ver el diff.

De todos modos este es el código equivalente Ruby:

class Fish 
    def initialize 
    @var = 'fish' 
    end 

    def v 
    @var 
    end 
end 

class Trout < Fish 
    def initialize 
    @var = 'trout' 
    end 
end 

class Salmon < Fish 
    def initialize 
    @var = 'salmon' 
    end 
end 

puts Trout.new.v 
puts Salmon.new.v 
+0

No es realmente así, porque debe sobrescribir la inicialización cada vez que subclase. Lo cual no es muy útil. Puede haber sido mejor en mi ejemplo incluir algún código en initialize. –

21

Para contrastar @ respuesta de khelll, este utiliza variables de instancia de los objetos Class:

class Fish 
    # an instance variable of this Class object 
    @var = 'fish' 

    # the "getter" 
    def self.v 
    @var 
    end 

    # the "setter" 
    def self.v=(a_fish) 
    @var = a_fish 
    end 
end 

class Trout < Fish 
    self.v = 'trout' 
end 

class Salmon < Fish 
    self.v = 'salmon' 
end 

p Trout.v # => "trout" 
p Salmon.v # => "salmon" 

Editar: a dar ejemplos lectura acceso a la variable de instancia de la clase:

class Fish 
    def type_of_fish 
    self.class.v 
    end 
end 

p Trout.new.type_of_fish # => "trout" 
p Salmon.new.type_of_fish # => "salmon" 
+0

No, no del todo. No estás haciendo Trout.new o Salmon.new al final. Estás usando la clase en sí. Quiero que la * instancia * obtenga las variables de clase. –

+0

@The Doctor - ¿y ahora? –

+0

Sí. Creo que ahora es funcionalmente equiv. a la respuesta que di. Solo está escribiendo los accesos manualmente. –

2

Es un error común que hacen los programadores de Java al llegar a Ruby, y uno de los grandes saltos conceptuales que tuve que resolver. Al principio parece extraño, pero en realidad es uno de los aspectos más interesantes de Ruby: todo el código es ejecutable, incluidas las definiciones de clases.

Por lo tanto, las variables de instancia se deben declarar dentro de los métodos. Tiene que ver con cómo se evalúa el "yo". 'uno mismo' es el objeto actual. El intérprete operaciones de búsqueda llamadas a métodos y las referencias a variables primero en 'auto':

class Fish 
    @var = "foo" # here 'self' == Fish, the constant which contains the class object 
    def foo 
     # do foo 
    end 
end 

fish = Fish.new 
fish.foo # here 'self' == fish, an instance of Fish 

En una definición de clase, 'yo' se establece para ser el objeto de la clase que se define, por lo que cualquier referencia dentro de una definición de clase se refieren a ese objeto de clase, en este caso Fish.

Cuando se invoca un método en una instancia de Fish, sin embargo, self se establece para ser el receptor de la llamada, la instancia particular de Fish. Entonces, fuera de una definición de método, el yo es el objeto de clase. Dentro de un método, self es la instancia del receptor. Esta es la razón por la cual @var fuera de una definición de método es más parecido a una variable estática en Java, y @var dentro de una definición de método es una variable de instancia.

+0

Typo: 'fish.foo' debe ser' fish.var' –

+0

En realidad, no. No definí 'foo', pero el punto era que el intérprete de Ruby vería a 'pez' como el receptor de la llamada y se pondría a 'pescar' para resolver la referencia. Aunque he agregado el método foo por claridad. Llamar 'fish.var' arrojaría un NoMethodError. –

+0

Ah. Mi error. Gracias por explicarlo. –

4

Aquí está la versión que terminé averiguar usando el enlace de hobodave:

class Fish 
    class << self 
    attr_accessor :var 
    end 

    @var = 'fish' 
    def v 
    self.class.var 
    end 
end 

class Trout < Fish 
    @var = 'trout' 
end 

class Salmon < Fish 
    @var = 'salmon' 
end 

puts (Trout.new).v # => trout 
puts (Salmon.new).v # => salmon 

en cuenta que una subclasificación sólo requiere la adición de un @var - no hay necesidad de reemplazar initialize.

1

No es un un problema: se puede anular @var:
Salmon.var = 'tiburón' anulará @var, por lo
puts (Salmon.new) .v = #> tiburón

Cuestiones relacionadas