2011-01-07 16 views
17

exención de responsabilidad: Código tomado de la ruby koansRuby: alcance explícita en una definición de clase

Se trata de una discusión de las constantes de alcance dentro de las clases. Aquí está el Defintion de un par de pocas clases:

class Animal 
    LEGS = 4 
    def legs_in_animal 
    LEGS 
    end 
end 

class MyAnimals 
    LEGS = 2 

    class Bird < Animal 
    def legs_in_bird 
     LEGS 
    end 
    end 
end 

En este punto haciendo MyAnimals::Bird.new.legs_in_bird resultados en 2 y entiendo por qué - buscar espacio léxica para la constante antes de la jerarquía de herencia.

A continuación, se define esta clase:

class MyAnimals::Oyster < Animal 
    def legs_in_oyster 
    LEGS 
    end 
end 

El tutorial dice que ahora llamando MyAnimals::Oyster.new.legs_in_oyster resultados en 4 y no puedo entenderlo. Me parece que Oyster es una clase anidada en MyAnimals y, como tal, esperaba que se comportara de la misma manera que la clase Birds de arriba. Me falta algo de información clave sobre lo que significa declarar la clase Oyster con un alcance explícito.

¿alguien me puede explicar esto? Encontré cientos de tutoriales de clase de ruby ​​a través de Google, pero ninguno de ellos aborda esta situación.

gracias de antemano ...

+3

Hay. Son. LAS CUATRO. ¡¡¡Piernas!!! zetetic

+0

Cuatro patas buenas, dos patas malas

+3

¿Alguien escribe código que dependería de qué constante se alcanzaría primero? –

Respuesta

17

Creo que this example lo explica mejor.Rubí busca para la definición constante en este orden:

  1. El alcance de encerramiento
  2. Cualquier ámbitos exteriores (repetir hasta que el nivel superior se alcanza) Cualquier ámbitos exteriores (hasta, pero no incluyendo el nivel superior
  3. módulos incluidos
  4. superclase (EN)
  5. de nivel superior
  6. objeto
  7. Kernel

EDITAR

Gracias a Mark Amery para señalar este error. El nivel superior solo se alcanza en el caso donde no hay ámbitos y/o superclases adjuntos. El ejemplo vinculado lo deja claro, lamentablemente lo leí mal.

Un ejemplo para este caso:

FOO = 'I pity the foo!' 

module One 
    FOO = 'one' 

    class Two 
    FOO = 'two' 

    def self.foo 
     FOO 
    end 
    end 

    class Three < Two 
    def self.foo 
     FOO 
    end 
    end 
end 

class Four 
    class Five < Four 
    def self.foo 
     FOO 
    end 
    end 
end 

describe FOO do 
    it "depends where it is defined" do 
    expect(FOO).to eq 'I pity the foo!' # top-level 
    expect(One::FOO).to eq 'one' # module 
    expect(One::Two.foo).to eq 'two' # class 
    expect(One::Three.foo).to eq 'one' # outer scope (One) comes before superclass 
    expect(Four::Five.foo).to eq 'I pity the foo!' # top-level 
    end 
end 
+0

¿Qué constituye el 'nivel superior'? Si hago 'FOO = 'topoffile'; prueba de clase; FOO = 'insuperclass'; fin; clase Test2

+0

@MarkAmery buena captura. – zetetic

5

Si define el Oyster DENTRO de la definición de clase MyAnimals, se obtiene la respuesta que es legs_in_oyster 2.

Si define el Oyster separado - que es , lo define después de que LEGS = 2 ha salido del ámbito, obtiene la respuesta de 4.

Esto me sugiere que la clase anidada se comporta de manera diferente a como lo hace un espacio de nombres, tal vez más como un cierre.

--- --- EDITAR

irb(main):076:0> class MyAnimals::RunningRoach < Animal; def using_legs; LEGS; end; end 
=> nil 
irb(main):077:0> MyAnimals::RunningRoach.new.kind_of?(MyAnimals) 
=> false 
irb(main):078:0> MyAnimals::RunningRoach.new.kind_of?(Animal) 
=> true 
irb(main):081:0> class MyAnimals::Mantis < MyAnimals; def killing_legs; LEGS; end; end 
=> nil 
irb(main):082:0> MyAnimals::Mantis.new.kind_of?(Animal) 
=> false 
irb(main):083:0> MyAnimals::Mantis.new.kind_of?(MyAnimals) 
=> true 
irb(main):084:0> MyAnimals::Mantis.new.killing_legs 
=> 2 
irb(main):085:0> MyAnimals::RunningRoach.new.using_legs 
=> 4 

De acuerdo con "The Ruby Programming Language", las constantes se buscan en el ámbito léxico del lugar en que se utilizaron por primera vez, y en la segunda jerarquía de herencia . Entonces, ¿cuál es el alcance léxico de algo que hereda Animal? Animal en sí, ¿verdad? La clase MyAnimals redefine LEGS, por lo que cualquier cosa que use LEGS, y se define dentro de MyAnimals, buscará LEGS dentro de MyAnimals primero.

+0

Ah, estaba pensando que independientemente de dónde definiera la clase, el acto de hacer MyAnimals :: lo convirtió en una clase anidada y le dio acceso a ese alcance ... – jaydel

Cuestiones relacionadas