2014-07-27 29 views
5

tôi đọc rằng đoạn mã dưới đây thực hiện những gì được gọi phần lớp:Lớp học ruby ​​một phần là gì?

class A 
    def a 
    puts 'a' 
    end 
end 

class B < A 
    def ba1 
    puts 'ba1' 
    end 
end 

class A 
    def b 
    puts 'b' 
    end 
end 

class B < A 
    def ba2 
    puts 'ba2' 
    end 
end 

ob = B.new 
ob.a 
ob.b 
ob.ba1 
ob.ba2 

Có hai lớp B kéo dài từ hai lớp A. Tôi không hiểu làm thế nào ruby ​​có thể biết được A các B là mở rộng từ. Khi tạo một thể hiện của B, làm sao ruby ​​biết được số nào là B? Kết quả thực hiện là:

a 
b 
ba1 
ba2 

sự khởi B là một thể hiện của hai B lớp. Ai đó có thể giải thích điều này?

+0

Cảm ơn @ Jörg W Mittag đã sửa tôi về định nghĩa "lớp học một phần". Tôi đã đi qua tất cả các câu trả lời, và tôi nghĩ tất cả các bạn đều đúng. Nhưng Uri Agassi đã rõ ràng và đơn giản hơn, tôi muốn chọn nó như là giải pháp cho những người khác tham khảo. Cảm ơn tất cả một lần nữa. – zgcharley

Trả lời

7

Khi bạn viết một lớp trong Ruby mà là đã tuyên bố, bạn không override lớp, nhưng thay vì nó.

Điều này có nghĩa là ruby ​​không quên định nghĩa cũ hơn, mà là thêm vào nó.

Chỉ có một lớp B - đó là mã ghép trong cả hai khối class B.

Ví dụ:

class A 
    def a 
    puts 'a' 
    end 
end 

a = A.new 
a.public_methods(false) 
# => [:a] 

class A 
    def b 
    puts 'b' 
    end 
end 

a.public_methods(false) 
# => [:a, :b] 

Trong ví dụ này, lớp A được thay đổi sau trường hợp của a được tạo ra, nhưng, như bạn thấy, nó biết rằng một phương pháp mới đã được bổ sung (public_methods liệt kê các phương thức có sẵn cho cá thể).

Có những điều bạn không thể làm, ví dụ - thay đổi lớp cha của lớp. Nếu chúng ta cố gắng để có những mã trên, và tuyên bố một khối:

class A < String 
    def c 
    puts 'c' 
    end 
end 
# TypeError: superclass mismatch for class A 

Bạn nhận được một lỗi nói rằng bạn đang cố gắng để thay đổi lớp cơ sở, đó là bất khả thi (nếu trong tờ khai ban đầu không có tuyên bố thừa kế, lớp được thừa kế hoàn toàn từ Object)

5

Chỉ có lớp B được thừa kế từ A. Bí quyết là bạn có thể tự do tuyên bố B ở những nơi khác nhau (trong đó, rõ ràng, cho phép bạn monkeypatch lớp hiện có.)

Một khi bạn đã class B < A viết tay, các B hiện đang được mở cho việc mở rộng, hoặc một mới một bản đang được tạo, nếu không có lớp B nào được xác định.

Hy vọng điều đó sẽ hữu ích.

1

Định nghĩa lớp Ruby có thể được định nghĩa lại. Thứ hai class A chỉ cần thêm các phương thức mới vào lớp hiện có. Số thứ hai class B < A tương tự mở rộng định nghĩa của B.

1
# In Ruby writing 

class A 
    def a; puts 'a' end 
end 

class A 
    def b; puts 'b' end 
end 

# is same as writing 

class A 
    def a; puts 'a' end 
    def b; puts 'b' end 
end 
3

Không có thứ như "các lớp một phần" trong Ruby. Các lớp một phần là một tính năng của C#, chứ không phải Ruby.

Trong Ruby, một biểu thức định nghĩa lớp sẽ thực thi bất kỳ thứ gì bên trong nó trong ngữ cảnh của lớp. Bạn có thể có nhiều biểu thức khai báo lớp như bạn muốn, nó không quan trọng. Điều này cho phép bạn định nghĩa từng phần của lớp, ngay cả trong các tệp khác nhau, ngay cả trong các thư viện khác nhau. Nó cũng cho phép ai đó khác để (lại) xác định lớp học của bạn sau này. Trong Python, điều này được gọi là "khỉ vá" và thường cau mày, cộng đồng Ruby đã áp dụng thuật ngữ này nhưng với một ý nghĩa trung lập, bởi vì, trong Ruby thực sự là tất cả các định nghĩa lớp là khỉ vá!

Vì vậy, những gì bạn có trên

  1. sẽ Sửa đổi định nghĩa lớp của A nếu A đã tồn tại hoặc tạo ra một lớp mới nếu nó không.
  2. Sửa đổi định nghĩa lớp học B nếu B đã tồn tại hoặc tạo một lớp mới nếu không. (Nên B đã tồn tại nhưng có một lớp cha khác nhau mà không phải là A, điều này sẽ nâng cao một TypeError "superclass mismatch".)
  3. Sửa đổi định nghĩa lớp của A (kể từ A đã được xác định).
  4. Sửa đổi định nghĩa lớp học B (kể từ khi B đã được xác định). Chúng tôi có thể đã bỏ qua siêu lớp, trong trường hợp đó, lớp cha hiện tại của B (tức là A) sẽ được giả định.

Nhân tiện: nói kỹ thuật, AB không phải là lớp học. Chúng là các biến (chính xác hơn, hằng số) mà tham chiếu cho các lớp. Các lớp là các đối tượng giống như các biến khác, chúng có thể được tham chiếu bởi các biến, được chuyển thành các đối số cho các phương thức, được trả về từ các phương thức, vv. biểu hiện:

class Foo < if rand < 0.5 then String else Array end 
end 

là hoàn toàn hợp lệ (và hoàn toàn vô dụng ;-))

class Foo < Bar; end 

def qux(sym); const_get(sym) end 

class Foo < qux(:Bar); end 

cũng là hoàn toàn hợp lệ và sẽ không tạo ra sự không phù hợp cha, bởi vì hằng Bar và phương pháp gọi qux(:Bar) cả hai đều trả về cùng một đối tượng (đó là một lớp).

Các vấn đề liên quan