Trước hết hãy làm một điều rõ ràng. Khi họ gọi super
bên trong class_eval
- điều đó hoàn toàn không liên quan gì đến lý do họ sử dụng điều include Module.new {}
. Trên thực tế, super
được gọi bên trong phương thức destroy
hoàn toàn không liên quan để trả lời câu hỏi của bạn. Có thể có bất kỳ mã tùy ý nào bên trong phương thức hủy đó.
Bây giờ chúng tôi đã loại bỏ nó, đây là những gì đang diễn ra.
Trong ruby, nếu bạn chỉ định nghĩa một phương thức lớp, và sau đó xác định lại nó trong cùng một lớp, bạn sẽ không thể gọi super
để truy cập phương thức trước đó.
Ví dụ:
class Foo
def foo
'foo'
end
def foo
super + 'bar'
end
end
Foo.new.foo # => NoMethodError: super: no superclass method `foo' for #<Foo:0x101358098>
này có ý nghĩa, bởi vì foo
đầu tiên không được định nghĩa trong một số lớp cha, hoặc bất cứ nơi nào trong chuỗi tra cứu (đó là nơi super
điểm). Tuy nhiên, bạn có thể xác định foo
đầu tiên theo cách sao cho sau này bạn ghi đè lên - nó sẽ có sẵn bằng cách gọi super
. Đây là chính xác những gì họ muốn đạt được với mô-đun bao gồm.
class Foo
include Module.new { class_eval "def foo; 'foo' end" }
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
Điều này có tác dụng, bởi vì khi bạn bao gồm một mô-đun, ruby sẽ chèn nó vào chuỗi tra cứu. Bằng cách này, bạn có thể gọi super
theo phương pháp thứ hai và mong đợi phương thức được bao gồm được gọi. Tuyệt quá.
Tuy nhiên, bạn có thể thắc mắc, tại sao không chỉ đơn giản bao gồm một mô-đun mà không có tất cả các thủ thuật? Tại sao họ sử dụng cú pháp khối? Chúng tôi biết rằng ví dụ trên của tôi giống hệt như sau:
module A
def foo
'foo'
end
end
class Foo
include A
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
Vậy tại sao họ không làm điều đó? Câu trả lời là - gọi tới số reflection
.Họ cần nắm bắt biến (hoặc phương pháp) có sẵn trong ngữ cảnh hiện tại, là reflection
.
Vì chúng đang xác định mô-đun mới sử dụng cú pháp khối, tất cả các biến bên ngoài khối có sẵn để sử dụng bên trong khối. Tiện lợi.
Chỉ để minh họa.
class Foo
def self.add_foo_to_lookup_chain_which_returns(something)
# notice how I can use variable something in the class_eval string
include Module.new { class_eval "def foo; '#{something}' end" }
end
end
# so somewhere else I can do
class Foo
add_foo_to_lookup_chain_which_returns("hello")
def foo
super + " world"
end
end
Foo.new.foo # => "hello world"
Gọn gàng, huh?
Bây giờ, hãy để tôi nhấn mạnh lại. Cuộc gọi tới super
bên trong phương thức destroy
trong ví dụ của bạn không liên quan gì đến bất kỳ điều nào ở trên. Họ gọi nó vì những lý do riêng của họ, bởi vì có thể lớp học mà điều này đang xảy ra là phân lớp một lớp khác đã được định nghĩa là destroy
.
Tôi hy vọng điều này đã rõ ràng.
có thể ping các nhân vật cốt lõi của đường ray? – rogerdpack