2017-10-07 28 views
5

Trong Metaprogramming Ruby 2 trong Chương 2 tại "bộ lọc" phần tôi thấy các đoạn mã sau đây Ruby:cải tiến của Ruby gotchas

class MyClass 
    def my_method 
    "original my_method()" 
    end 

    def another_method 
    my_method 
    end 

end 

module MyClassRefinement 
    refine MyClass do 
    def my_method 
     "refined my_method()" 
    end 
    end 
end 

using MyClassRefinement 
MyClass.new.my_method # => "refined my_method()" 
MyClass.new.another_method # => "original my_method()" - How is this possible? 

Theo tác giả:

Tuy nhiên, cuộc gọi đến another_method có thể khiến bạn mất cảnh giác: ngay cả khi bạn gọi another_method sau using, cuộc gọi đến my_method chính nó xảy ra trước using - do đó, nó gọi phiên bản gốc, chưa tinh chế của phương thức.

Điều này hoàn toàn theo dõi tôi.

Tại sao MyClass.new.another_method in "original my_method()" kể từ khi được sử dụng sau using MyClassRefinement và tác giả đang cố gắng nói gì ở đây?

Có ai có thể cung cấp giải thích trực quan/tốt hơn không?

Cảm ơn.

+0

Có thể do bản đồ được giới thiệu bởi các sàng lọc chỉ áp dụng cho một phạm vi cụ thể và trong phạm vi định nghĩa ban đầu đó phạm vi không bị ảnh hưởng. – tadman

Trả lời

2

Lời giải thích tốt nhất mà tôi có thể tìm thấy là từ the docs:

sàng lọc là các từ vựng trong phạm vi. Các sàng lọc chỉ hoạt động trong phạm vi sau khi gọi tới số using. Bất kỳ mã nào trước câu lệnh using sẽ không được kích hoạt sàng lọc.

Điều đó có nghĩa là phương pháp sàng lọc của bạn phải được gọi ở đâu đó sau khi gọi đến using. Vị trí thực tế của lời gọi của phương thức là những gì quan trọng, không phải cách thức mà phương thức được gọi hoặc từ nơi mà phương thức được gọi.


Đây là những gì sẽ xảy ra.

  1. using tức là using MyClassRefinement kích hoạt sàng lọc my_method.
  2. MyClass.new.my_method được thực hiện.
  3. Một method lookup nảy sinh từ quan điểm chính xác của invocation:

Khi nhìn lên một phương pháp cho một thể hiện của class C kiểm tra Ruby:

  • Nếu cải tiến đang hoạt động cho C, trong ngược thứ tự chúng được kích hoạt
    • Các mô-đun được thêm vào từ sàng lọc cho C
    • Những cải tiến cho C
    • Các module hỗ trợ từ sự tinh tế cho C
  • Các module được thêm vào trước các C
  • C
  • Các module bao gồm các C
  1. bộ lọc đang hoạt động, và my_method trả về mã từ tinh "refined my_method()"
  2. MyClass.new.another_method được thực thi.
  3. method lookup xảy ra sau thời điểm yêu cầu chính xác.
  4. sàng lọc đang hoạt động tại thời điểm này, nhưng another_method không phải là sàng lọc, vì vậy Ruby tìm kiếm another_method trong lớp MyClass và tìm thấy nó.
  5. Bên trong phương thức lớp another_method, phương thức my_method được tìm thấy và gọi.
  6. method lookup xảy ra sau thời điểm yêu cầu chính xác. Tại thời điểm yêu cầu không có sàng lọc nào đang hoạt động, vì không có cuộc gọi nào đến số usingphía trên dòng (tức là trước đây về mặt vật chất), trong đó my_method được gọi. Ruby tiếp tục tìm kiếm my_method trong lớp MyClass và tìm thấy nó.
  7. my_method trả về mã từ phương thức lớp "original my_method()".

Chúng ta có thể làm một so sánh đơn giản. Hãy nói rằng tôi có một cô lập file.rb với đoạn mã sau:

puts puppy 
puppy = 'waggle' 

puppy không thể được sử dụng trước khi nó được định nghĩa. Biến được lexically scoped, và sử dụng của nó phụ thuộc vào vị trí của định nghĩa của nó trong file.rb bị cô lập.

Tương tự, không thể gọi sàng lọc cho đến khi được kích hoạt qua using trên dòng trước đó (hoặc ở nơi nào đó trước đây trong tệp mã nguồn). Tinh lọc là lexically scoped.

From Wikipedia

Trong các ngôn ngữ với phạm vi từ vựng (còn gọi là tĩnh phạm vi), độ phân giải tên phụ thuộc vào vị trí trong mã nguồn và bối cảnh từ vựng, được định nghĩa bởi nơi biến hoặc chức năng được đặt tên được xác định ...

Độ phân giải Lexical có thể được xác định tại thời gian biên dịch và còn được gọi là liên kết sớm, trong khi độ phân giải động có thể nói chung chỉ được xác định tại thời gian chạy, và do đó được gọi là cuối ràng buộc.


vấn đề cụ thể của bạn với cải tiến sẽ được thảo luận trong phần cuối cùng của this article. Tác giả giải thích cũng như cách vị trí thực tế của tuyên bố using trong tệp xác định có hay không một sàng lọc đang hoạt động.

+0

Cảm ơn bạn! Nó có ý nghĩa hoàn toàn ngay bây giờ! Phạm vi Lexical là thủ phạm thực sự. – kstratis

+0

... và tài liệu tham khảo của bạn đã giúp ích rất nhiều! – kstratis

+0

Không vấn đề gì :) Tôi vui vì nó đã giúp –

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