2011-01-07 26 views
17

免責聲明:從ruby koans紅寶石:一類定義明確的範圍界定

這是從類中的作用域常數的討論採取代碼。這是一對夫婦的幾節課的確定指標:

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 

在這一點上做的MyAnimals::Bird.new.legs_in_bird結果2,我明白爲什麼 - 繼承層次結構之前,搜索常數詞法空間。

那麼這個類的定義:

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

本教程說,現在要求MyAnimals::Oyster.new.legs_in_oyster導致4,我不能弄明白。在我看來,Oyster是MyAnimals中的一個嵌套類,因此我期望它的行爲與Birds類的行爲相同。我錯過了一些關於使用顯式範圍方法聲明類Oyster的關鍵信息。

任何人都可以向我解釋這個嗎?我已經通過谷歌發現了數百個ruby類教程,但沒有一個能夠解決這種情況。

預先感謝您...

+3

有。是。四。腿! zetetic 2011-01-07 19:07:07

+0

四條腿很好,兩條腿不好 2011-02-17 22:30:52

+3

有沒有人編寫代碼,取決於哪個常量會先到達? – 2011-02-17 22:37:31

回答

17

我認爲this example最好解釋。紅寶石搜索的順序的常數的定義:

  1. 封閉範圍
  2. 任何外部範圍(重複,直到頂層到達) 任何外部範圍(高達但不包括頂層
  3. 包括模塊
  4. 超類(ES)
  5. 頂級
  6. 對象
  7. 內核

編輯

感謝Mark Amery指出這個錯誤。只有在沒有封閉範圍和/或超類的情況下才能達到頂層。鏈接的例子實際上使這個清楚,可悲的是我讀錯了。

對於這種情況下的一個例子:

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 
5

如果定義了牡蠣裏面MyAnimals類的定義,那麼你得到的答案是legs_in_oyster爲2

如果分別定義牡蠣 - 這是,你在LEGS = 2已經超出範圍之後定義它,你得到的響應爲4.

這表明嵌套類的行爲與名稱空間不同,也許更像閉包。

---編輯---

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 

據「Ruby編程語言」,常量是在他們第一次使用的地方的詞彙範圍,擡起頭來,在繼承層次第二。那麼繼承動物的東西的詞彙範圍是什麼?動物本身,對吧? MyAnimals類重新定義了LEGS,因此任何使用LEGS的定義在 MyAnimals中的定義爲的任何內容都將首先在MyAnimal中查找LEGS。