10
class << self 
attr_accessor :n, :totalX, :totalY 
end 

Cú pháp trên được sử dụng để xác định biến thể hiện lớp. Nhưng khi tôi nghĩ về cú pháp ngụ ý, nó không có ý nghĩa gì với tôi, vì vậy tôi tự hỏi liệu loại cú pháp này có được sử dụng cho bất kỳ loại định nghĩa nào khác không. Điểm của tôi về sự nhầm lẫn ở đây là:Trong Ruby có bất kỳ ứng dụng liên quan nào của cú pháp: lớp << tự ... kết thúc

class << self 

Toán tử nối tiếp thường có nghĩa là "thêm những gì ở bên phải đối tượng ở bên trái". Nhưng trong bối cảnh của khối này, làm thế nào để thêm vào "đặt nội dung của khối này vào định nghĩa của cá thể lớp chứ không phải là cá thể"?

Đối với cùng một lý do tôi đang bối rối là tại sao trong một bối cảnh lớp < < tự có thể định nghĩa các biến lớp dụ trong khi khác có vẻ như để tạo ra các biến lớp học như ở đây:

class Point 
    # Instance methods go here 
    class << self 
    # Class methods go here 
    end 
end 

Trả lời

18

trong Ruby bạn có thể mở lại các lớp hiện có và thêm phương thức. Nghĩa là, bạn có thể nói:

class Foo 
    def bob 
    return "hello from bob" 
    end 
end 

những phương pháp được lưu trữ ở đâu đó trong một cuốn từ điển nội bộ (có thể một biến chẳng hạn) của Foo đẳng cấp (mà chỉ là một thể hiện của các Class đẳng cấp và do đó biến chẳng hạn)

Nhưng điều đáng ngạc nhiên là, bạn cũng có thể thêm các phương pháp để trường của các đối tượng hiện có

foo = Foo.new 
foo2 = Foo.new 

def foo.fred 
    return "I am fred" 
end 


foo.fred #=> "I am fred" 
foo2.fred #=> NoMethodError 

nhưng Phương pháp này thực sự được lưu trữ ở đâu?

Hóa ra của Ruby tạo một lớp mới đằng sau hậu trường (đôi khi được gọi singleton lớp, metaclass hoặc eigenclass) mà được đưa vào hệ thống cấp bậc thừa kế giữa các Foo đẳng cấp và cá thể của nó.

Vì vậy, mối quan hệ thừa kế trông giống như rằng:

foo < (eigenclass of foo) < Foo < Class 

(nếu bạn nói foo.superclass bạn sẽ không thấy lớp singleton)

class << X -syntax là một cách để đến lớp đặc biệt này, để bạn có thể thao tác trực tiếp. Các khối mã sau đây là chính xác tương đương:

def foo.bar 
    return "xy" 
end 

# is exactly the same as 

class << foo 
    def bar 
    return "xy" 
    end 
end 

Vì vậy, sự giống nhau giữa class Foo < Barclass << Foo không phải là ngẫu nhiên, có thừa kế xảy ra trong cả hai.

Hãy suy nghĩ về class << X là "mở ra metaclass của X"

Những điều cần nhớ trong Ruby là lớp mình chỉ là các đối tượng. (Trường hợp của lớp Class) vì vậy nếu bạn nói:

class Foo 
    class << self 
    def k 
     return "x" 
    end 
    end 
end 

(self là ràng buộc để Foo trong khối mã này) để k là một phương pháp dụ của eigenclass của Foo, mà làm cho nó một phương pháp học cho Foo

tất cả điều này được giải thích rõ ràng hơn trong chapter about classes of the Pickaxe (phiên bản web không chứa sơ đồ, không may) và _whys Seeing Metaclasses Clearly

2

suy nghĩ của lớp có chứa một từ điển của các thành viên bao gồm tất cả các biến và các biến cá thể. Khi bạn yêu cầu lớp học "chắp thêm" vào "chính nó", bạn đang nói "thêm chúng vào từ điển của các thành viên lớp học".

Tôi sẽ cấp ký hiệu là một chút hinky.

+0

Ok - rằng' là một cách hay để xem - lớp thực sự là một từ điển. Nhưng thực ra bạn đã trả lời trước khi tôi thêm ví dụ cuối cùng của mình vào một ngữ cảnh khác cùng một sytax (theo cuốn sách tôi đang đọc), tạo ra các phương thức lớp thay vì các phương thức của lớp. Tại sao ví dụ lớp Point ở kết quả cuối cùng trong một phương thức lớp trong khi attr_accessor ở trên cùng cung cấp cho bạn các thuộc tính ở cấp độ cá thể lớp? –

+0

Trên thực tế sử dụng lời giải thích bạn đã cho tôi có thể trả lời câu hỏi trong bình luận trước của tôi - phương thức attr_accessor gọi các phương thức instance_variable_set và instance_variable_get của lớp Class. Thông thường, những kết quả đó sẽ tạo ra các biến mẫu được tạo ra nhưng vì chúng ta đang thêm vào từ điển lớp, khi bạn đặt nó, chúng ta đang tạo các biến cá thể lớp. Ok, tôi nghĩ rằng tôi đã có nó ngay bây giờ. Cảm ơn. –

+1

-1 gây hiểu nhầm, vì lớp << x ... cuối thực sự thêm thông tin vào metaclass của x chứ không phải lớp x. – rampion

1

thực sự khó hiểu khi nghĩ về điều đó về toán tử "nối thêm". một cách tốt hơn để xem xét nó là chỉ cần class Foo mở lớp Foo, tức là, nó đặt 'self' thành đối tượng lớp Foo, tạo nó nếu cần thiết, do đó, class << self mở ra eigenclass của đối tượng 'self' hiện tại. lưu ý rằng nó không chỉ giới hạn ở bản thân - đối với bất kỳ thanh đối tượng nào, bạn có thể nói loại < thanh < để mở eigenclass của đối tượng đó.

class A 
    def hello 
    print "hello world" 
    end 
end 

a = A.new 
b = A.new 

class << a 
    def goodbye 
    print "goodbye cruel world" 
    end 
end 

a.hello 
b.hello 
a.goodbye 
b.goodbye 
Các vấn đề liên quan