24 Stimmen

Ruby: explizites Scoping bei einer Klassendefinition

Haftungsausschluss: Der Code stammt aus der Rubinkoans

Dies stammt aus einer Diskussion über das Scoping von Konstanten innerhalb von Klassen. Hier ist die Definition einiger weniger Klassen:

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

Zu diesem Zeitpunkt tun MyAnimals::Bird.new.legs_in_bird ergibt 2 und ich verstehe, warum - suchen Sie im lexikalischen Raum nach der Konstante vor der Vererbungshierarchie.

Dann wird diese Klasse definiert:

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

Das Tutorial sagt, dass nun der Aufruf von MyAnimals::Oyster.new.legs_in_oyster Ergebnisse in 4 und ich kann es nicht herausfinden. Es scheint mir, dass Oyster eine verschachtelte Klasse in MyAnimals ist und als solche habe ich erwartet, dass sie sich genauso verhält wie die Klasse Birds oben. Mir fehlen einige wichtige Informationen darüber, was die Deklaration der Klasse Oyster mit explizitem Scoping bedeutet.

Kann mir das jemand erklären? Ich habe Hunderte von Ruby-Klasse-Tutorials über Google gefunden, aber keiner von ihnen Adresse diese Situation.

Ich danke Ihnen im Voraus...

3 Stimmen

<picard>Da. Sind. VIER. Beine!!!</picard>

1 Stimmen

<Tierfarm>Vier Beine gut, zwei Beine schlecht</animal farm>

4 Stimmen

Schreibt jemand Code, der davon abhängt, welche Konstante zuerst erreicht wird?

27voto

zetetic Punkte 46520

Ich denke dieses Beispiel erklärt es am besten. Ruby sucht in dieser Reihenfolge nach der Definition der Konstante:

  1. Der umschließende Bereich
  2. Beliebige äußere Bereiche (wiederholen, bis die oberste Ebene erreicht ist) Alle äußeren Geltungsbereiche (bis zu, aber ohne die oberste Ebene
  3. Enthaltene Module
  4. Oberklasse(n)
  5. Oberste Ebene
  6. Objekt
  7. Kernel

EDIT

Dank an Mark Amery dass Sie uns auf diesen Fehler hingewiesen haben. Die oberste Ebene wird nur dann erreicht, wenn es keine umschließenden Bereiche und/oder Superklassen gibt. Das verlinkte Beispiel macht dies eigentlich deutlich, leider habe ich es falsch gelesen.

Ein Beispiel für diesen Fall:

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

5voto

philosodad Punkte 1798

Wenn Sie die Auster INNERHALB der Klassendefinition von MyAnimals definieren, dann erhalten Sie die Antwort, dass legs_in_oyster 2 ist.

Wenn Sie die Auster separat definieren, d. h. nachdem LEGS = 2 den Bereich verlassen hat, erhalten Sie die Antwort 4.

Das deutet für mich darauf hin, dass sich die verschachtelte Klasse anders verhält als ein Namespace, vielleicht eher wie eine Schließung.

---EDIT---

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

Laut "The Ruby Programming Language" werden Konstanten zuerst im lexikalischen Bereich des Ortes gesucht, an dem sie verwendet werden, und dann in der Vererbungshierarchie. Was ist also der lexikalische Bereich von etwas, das Animal erbt? Animal selbst, richtig? Die Klasse MyAnimals definiert LEGS neu, so dass alles, was LEGS verwendet und definiert ist innerhalb MyAnimals, sucht zuerst nach LEGS innerhalb von MyAnimals.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X