2012-05-09 73 views
12

我知道ruby中的所有類都是元類Class的實例。而「常規」對象是這些類的實例(metaclass Class的實例)。但我一直想知道,我的意思是類是對象的根,類本身是類的實例(稱爲元類,因爲它的實例是類)。我在一些博客中看到了一些覆蓋類Class的方法newRuby元類困惑

因此,類表現爲一個類,但其實例是類。所以看起來我們有一個圈,它看起來很喜歡class Class,它本身就是一個實例。

我顯然在這裏忽略了一點。班級的起源是什麼?

這裏有一個交代不清的我舉一個例子:

class Class 
    def new 
    #something 
    end 
end 

但關鍵字class意味着Class類的一個實例。那麼這是如何工作的?

+4

'Class.class#=> Class' – Flexoid

+5

它一直都是烏龜! –

+0

另請參見[類/對象悖論混亂](http://stackoverflow.com/questions/7675774/the-class-object-paradox-confusion)。 –

回答

28

如何做好這項工作

簡單:它沒有。無論如何,不​​在Ruby中。

就像在其他大多數語言中一樣,有一些核心實體被簡單地假設存在。它們從天而降,變得空氣稀薄,奇蹟般地出現。

在Ruby中,其中的一些神奇的事情是:

  • Object沒有一個超類,但你不能沒有超定義一個類,隱含的直接超類總是Object。 [注意:可能有實現定義的超類Object,但最終會有一個沒有超類的。]
  • ObjectClass一個實例,這是Object子類(這意味着間接ObjectObject自身的實例)
  • Class被的Module一個子類,其是Class
  • Class一個實例是Class的一個實例

這些事情都不能在Ruby中解釋。

BasicObject,Object,ModuleClass都需要同時存在,因爲它們具有循環依賴性。

僅僅因爲這種關係不能用Ruby代碼表達,並不意味着Ruby語言規範不能說它必須如此。實現者需要找出一種方法來實現這一點。畢竟,Ruby實現對程序員不具備的對象有一定的訪問權限。

例如,Ruby實現可以先創建BasicObject,同時設置了superclass指針和class指針null

然後,它會創建Object,其superclass指針設置爲BasicObject及其class指針null

接下來,它會創建Module,其superclass指針設置爲Object及其class指針null

最後,它創建Class,其superclass指針設置爲Module及其class指針null。現在

,我們可以覆蓋BasicObject的,Object的,Module's和Classclass指針指向Class,我們就大功告成了。

這很容易從系統外部做,它看起來很奇怪。

然而,他們一旦確實存在,那麼完全可以在純Ruby中實現其大部分行爲。您只需要這些類的準系統版本,這要感謝Ruby的開放類,您可以稍後添加任何缺少的功能。

在您的例子中,class Class不創建一個名爲Class新的類,它被重新打開現有Class,這是由運行時環境給我們。

所以,這是完全可能的解釋平原紅寶石Class#new默認行爲:

class Class 
    def new(*args, &block) 
    obj = allocate # another magic thing that cannot be explained in Ruby 
    obj.initialize(*args, &block) 
    return obj 
    end 
end 

[注:實際上,initialize是私有的,所以你需要使用obj.send(:initialize, *args, &block)繞過訪問限制]

作者:Class#allocate是另一個那些神奇的東西。它在Ruby的對象空間中分配一個新的空對象,這是Ruby中無法做到的。因此,Class#allocate也必須由運行時系統提供。

+3

我想你的意思是「'BasicObject'的超類是'nil'',因爲'Object'的超類是'BasicObject'。 –

+2

@AndrewMarshall:這是1.9的新功能。 1.8只有'Object'沒有'BasicObject'。 –

+2

@HolgerJust沒錯,但1.8接近生命週期,除非提交者指定我假設最新版本的Ruby。 –

1

雖然它有點過時,但this article by _why可能有助於理解行爲。您可以在Paolo Perrotta的Metaprogramming Ruby中更深入地瞭解該主題。

+0

爲什麼說這裏與Parello使用「metaclass」這個詞沒有任何關係。他所談論的是單身人士課程,或更通俗地講,是特徵課程。 – Chuck

2

是的,類是它自己的一個實例。它是Module的一個子類,也是類的一個實例,Module是Object的子類,它也是Class的一個實例。這確實是相當循環的 - 但這是核心語言的一部分,而不是圖書館中的東西。在我們編寫Ruby代碼時,Ruby運行時本身並沒有與您或我做的相同的限制。

雖然我從來沒有聽說過「元類」這個詞用來談論Class。它在Ruby中並沒有太多用處,但是當它出現時,它通常是官方稱之爲「對象的單例類」的同義詞,它比Object-Module-Class三角形更令人困惑。

+1

事實上,根據一般定義,Class可以被稱爲元類。但是我錯誤地將世界元類用於許多紅寶石主義者的其他事情。但根據一般定義,這些元類是弱元類。如果我記得好的話,通常在ruby中稱爲元類的東西是持有類方法的單例。我已經閱讀了幾篇關於它的文章,說metaclass這個詞被錯誤地使用了,並且他們在這一點上責怪rails團隊。感謝大家。 – Perello

2

「twist」鏈接給出了一個meta-circularity。它是從根的本徵類到Class類的內置超類鏈接。這可以通過

BasicObject.singleton_class.superclass == Class 

甲線索來表示對理解.class地圖是看到此映射從eigenclass和超鏈接導出:對於對象xx.class處於x的超類鏈中的第一類eigenclass。這可以通過

x.class == x.eigenclass.superclass(n) 

其中eigenclasssingleton_class 一個「概念別名」(抗與立即值的問題)來表示,y.superclass(i)意味着yi個超類和n是最小的,使得x.eigenclass.superclass(n)是一個類。等效地,跳過x.eigenclass的超類鏈中的本徵類(參見rb_class_real,其也揭示了在MRI中,即使superclass鏈接也通過跳過「 iclasses」而間接地實現了–)。 這導致每個類(以及每個特徵類)的class始終是Class類。

圖片由this diagram提供。

元類混亂有2個主要來源:

  • Smalltalk的。 Smalltalk-80對象模型包含由Ruby對象模型糾正的概念不一致。另外,Smalltalk文獻在術語中使用辯證法,遺憾的是在Ruby文獻中尚未得到充分的補救。

  • 元定義。目前,定義指出元類是類的類。然而,對於所謂的「隱含元類」(Ruby和Smalltalk-80的情況),更合適的定義將是類對象的元對象