2012-05-09 46 views
12

Tôi hiểu rằng tất cả các lớp trong ruby ​​là các trường hợp của lớp metaclass. Và các đối tượng "thông thường" là các cá thể của các lớp này (các cá thể của lớp Metaclass). Nhưng tôi cứ tự hỏi, ý tôi là các lớp là gốc của các đối tượng, các lớp là chính các cá thể của Class (được gọi là metaclass vì các cá thể của nó là các lớp). Tôi đã thấy trong một số blog một số trọng tâm của phương pháp new, của lớp Class.Sự nhầm lẫn metaclass của Ruby

Lớp học hoạt động như một lớp học, nhưng các thể hiện của nó là các lớp. Vì vậy, có vẻ như chúng tôi có một vòng tròn, có vẻ như lớp học lớp học là một ví dụ của chính nó.

Tôi rõ ràng đã bỏ lỡ một điểm ở đây. Nguồn gốc của lớp học là gì?

Dưới đây là một ví dụ đó là khó hiểu cho tôi:

class Class 
    def new 
    #something 
    end 
end 

Nhưng từ khóa class ngụ ý một thể hiện của lớp Class. Vậy làm thế nào để làm việc này?

+4

'Class.class # => Class' – Flexoid

+5

Rùa là tất cả các con đường xuống! –

+0

Xem thêm [Sự lộn xộn nghịch lý lớp/đối tượng] (http://stackoverflow.com/questions/7675774/the-class-object-paradox-confusion). –

Trả lời

28

làm thế nào để làm việc này

dễ dàng: nó không. Không phải trong Ruby, dù sao đi nữa.

Giống như trong hầu hết các ngôn ngữ khác, có một số thực thể cốt lõi được cho là tồn tại đơn giản. Chúng rơi xuống từ bầu trời, hiện ra từ không khí mỏng, xuất hiện kỳ ​​diệu.

Trong Ruby, một số trong những điều kỳ diệu là:

  • Object không có một lớp cha, nhưng bạn không thể định nghĩa một lớp không có lớp cha, lớp cha trực tiếp ngầm luôn là Object. [Lưu ý: có thể có các lớp siêu thực hiện được xác định là Object, nhưng cuối cùng, sẽ có một lớp không có siêu lớp.]
  • Object là một thể hiện của Class, mà là một lớp con của Object (có nghĩa là gián tiếp Object là một thể hiện của Object chính nó)
  • Class là một lớp con của Module, đó là một thể hiện của Class
  • Class là một ví dụ của Class

Không có điều nào trong số này có thể được giải thích trong Ruby.

BasicObject, Object, ModuleClass tất cả cần phải đồng thời tồn tại cùng lúc vì chúng có phụ thuộc vòng tròn.

Chỉ vì mối quan hệ này không thể được thể hiện trong mã Ruby, không có nghĩa là đặc tả ngôn ngữ Ruby không thể nói nó phải như vậy. Nó tùy thuộc vào người triển khai để tìm ra cách để làm điều này. Sau khi tất cả, việc thực hiện Ruby có một mức độ truy cập vào các đối tượng mà bạn là một lập trình viên không có.

Ví dụ, việc thực hiện Ruby đầu tiên có thể tạo ra BasicObject, thiết lập cả superclass con trỏ của nó và class con trỏ của nó để null.

Sau đó, nó tạo ra Object, thiết lập con trỏ superclass của nó để BasicObjectclass con trỏ của nó để null.

Tiếp theo, nó tạo ra Module, thiết lập con trỏ superclass của nó để Objectclass con trỏ của nó để null.

Cuối cùng, nó tạo ra Class, thiết lập con trỏ superclass của nó để Moduleclass con trỏ của nó để null.

Bây giờ, chúng ta có thể ghi đè lên BasicObject 's, Object' s, Module 's, và Class' s class con trỏ để trỏ đến Class, và chúng tôi đang thực hiện.

Điều này rất dễ làm từ bên ngoài hệ thống, nó trông có vẻ lạ từ bên trong.

Khi chúng làm tồn tại, tuy nhiên, hoàn toàn có thể thực hiện hầu hết hành vi của chúng trong Ruby thuần túy. Bạn chỉ cần phiên bản barebones của các lớp đó, nhờ vào các lớp mở của Ruby, bạn có thể thêm bất kỳ chức năng bị thiếu nào sau này.

Trong ví dụ của bạn, class Class không tạo ra một lớp mới có tên Class, nó được mở lại lớp hiệnClass, được ban cho chúng ta bởi môi trường runtime.

Vì vậy, nó là hoàn toàn có thể giải thích hành vi mặc định của Class#new ở đồng bằng Ruby:

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 

[Lưu ý:. Trên thực tế, initialize là tư nhân, vì vậy bạn cần phải sử dụng obj.send(:initialize, *args, &block) để phá vỡ những hạn chế truy cập]

BTW: Class#allocate là một trong những điều kỳ diệu đó. Nó phân bổ một đối tượng rỗng mới trong không gian đối tượng của Ruby, đó là một thứ không thể thực hiện được trong Ruby. Vì vậy, Class#allocate là một cái gì đó phải được cung cấp bởi hệ thống thời gian chạy là tốt.

+3

Tôi nghĩ rằng bạn có nghĩa là "siêu lớp cơ bản' 'BasicObject' là' nil' ", như superclass' Object' là 'BasicObject'. –

+2

@AndrewMarshall: Tính năng mới trong phiên bản 1.9. 1.8 chỉ có 'Object' không có' BasicObject'. –

+2

@HolgerJust Đúng, nhưng 1.8 gần hết hạn, và trừ khi người hỏi chỉ định tôi giả sử phiên bản mới nhất của Ruby. –

1

Mặc dù nó hơi lỗi thời, this article by _why có thể giúp hiểu hành vi. Bạn có thể tìm hiểu sâu hơn về chủ đề trong số Metaprogramming Ruby của Paolo Perrotta.

+0

Điều gì Tại sao nói về không có gì để làm với việc Parello sử dụng từ "metaclass". Những gì anh ta nói về là lớp singleton hoặc, thông tục hơn, eigenclass. – Chuck

2

Có, Lớp học là một ví dụ của chính nó. Nó là một phân lớp của Module, cũng là một thể hiện của lớp, và Module là một lớp con của Object, cũng là một thể hiện của Class. Nó thực sự khá tròn - nhưng đây là một phần của ngôn ngữ cốt lõi, không phải là một cái gì đó trong một thư viện. Bản thân thời gian chạy Ruby không có cùng giới hạn cho bạn hoặc tôi làm khi viết mã Ruby.

Tôi chưa bao giờ nghe từ "metaclass" thường được sử dụng để nói về Lớp học. Nó không được sử dụng nhiều trong Ruby chút nào, nhưng khi đó, nó thường là một từ đồng nghĩa với cái gọi là "class singleton của một đối tượng", đó là một chủ đề còn khó hiểu hơn là Object-Module-Class triangle.

+1

Lớp thực tế có thể được gọi là metaclass, theo định nghĩa chung. Nhưng thế giới metaclass tôi nhầm lẫn được sử dụng cho những thứ khác bởi nhiều rubyist. Nhưng các metaclasses này là metaclasses yếu theo định nghĩa chung. Nếu tôi nhớ rõ những điều thường được gọi là metaclass trong ruby ​​là những người độc thân nắm giữ các phương pháp lớp học. Tôi đã đọc một số bài viết về nó, nói rằng metaclass từ đã được sử dụng sai lầm, và họ đổ lỗi cho đội đường ray vào thời điểm này. Cảm ơn mọi người. – Perello

2

Có một siêu vòng tròn được cung cấp bởi liên kết "xoay". Nó là liên kết siêu lớp dựng sẵn từ eigenclass của gốc đến lớp Class. Điều này có thể được thể hiện bằng

BasicObject.singleton_class.superclass == Class 

Một đầu mối để tìm hiểu bản đồ .class được nhìn thấy bản đồ này là bắt nguồn từ eigenclass và các liên kết lớp cha: cho một đối tượng x, x.class là lớp đầu tiên trong chuỗi lớp cha của x 's eigenclass. Điều này có thể được thể hiện bằng

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

nơi eigenclass là một "bí danh khái niệm" của singleton_class (đề kháng với các vấn đề với các giá trị tức thời), y.superclass(i) nghĩa i lớp cha -thứ của yn là nhỏ nhất mà x.eigenclass.superclass(n) là một lớp . Tương tự, eigenclasses trong chuỗi siêu lớp của x.eigenclass bị bỏ qua (xem rb_class_real cũng cho thấy rằng trong MRI, thậm chí superclass liên kết được thực hiện gián tiếp – chúng phát sinh bằng cách bỏ qua " iclasses"). Điều này dẫn đến kết quả là class của mỗi lớp học (cũng như của mỗi lớp học eigenclass) liên tục là lớp học Class.

Ảnh được cung cấp bởi this diagram.

Các metaclass nhầm lẫn có 2 nguồn chính:

  • Smalltalk. Mô hình đối tượng Smalltalk-80 chứa các mâu thuẫn khái niệm được chỉnh sửa bởi mô hình đối tượng Ruby. Ngoài ra, văn học Smalltalk sử dụng biện chứng biện chứng trong thuật ngữ, mà không may đã không được khắc phục đầy đủ trong văn học Ruby.

  • Định nghĩa của metaclass. Hiện tại, định nghĩa chỉ ra rằng metaclasses là các lớp của các lớp. Tuy nhiên, đối với cái gọi là " metaclasses tiềm ẩn" (trường hợp của Ruby và Smalltalk-80), một định nghĩa phù hợp hơn sẽ là của meta-objects của các lớp.