Sự khác biệt giữa bao gồm và yêu cầu trong Ruby là gì?


465

Câu hỏi của tôi tương tự như " Sự khác biệt giữa bao gồm và mở rộng trong Ruby là gì? ".

Sự khác biệt giữa requireincludetrong Ruby là gì? Nếu tôi chỉ muốn sử dụng các phương thức từ một mô-đun trong lớp của mình, tôi requirenên hay includenó?


1
Đối với những gì nó có giá trị, đây là các liên kết đến tài liệu cộng đồng requireinclude, và cũng có liên quan , Module#append_features.

Câu trả lời:


543

Sự khác biệt giữa "bao gồm" và "yêu cầu" trong Ruby là gì?

Câu trả lời:

Các phương pháp bao gồm và yêu cầu làm những việc rất khác nhau.

Phương thức yêu cầu thực hiện những gì bao gồm trong hầu hết các ngôn ngữ lập trình khác: chạy tệp khác. Nó cũng theo dõi những gì bạn yêu cầu trong quá khứ và sẽ không yêu cầu cùng một tệp hai lần. Để chạy một tệp khác mà không có chức năng bổ sung này, bạn có thể sử dụng phương thức tải.

Phương thức bao gồm lấy tất cả các phương thức từ một mô-đun khác và đưa chúng vào mô-đun hiện tại. Đây là một điều ở cấp độ ngôn ngữ trái ngược với điều ở cấp độ tệp như yêu cầu. Phương thức bao gồm là cách chính để "mở rộng" các lớp với các mô-đun khác (thường được gọi là hỗn hợp). Ví dụ, nếu lớp của bạn định nghĩa phương thức "mỗi", bạn có thể bao gồm mô-đun mixin Enumerable và nó có thể hoạt động như một bộ sưu tập. Điều này có thể gây nhầm lẫn vì động từ bao gồm được sử dụng rất khác nhau trong các ngôn ngữ khác.

Nguồn

Vì vậy, nếu bạn chỉ muốn sử dụng một mô-đun, thay vì mở rộng nó hoặc thực hiện một hỗn hợp, thì bạn sẽ muốn sử dụng require.

Lạ lùng thay, Ruby requirelà tương tự như C include, trong khi Ruby includelà gần như không có gì giống như C include.


45
Trong thực tế C bao gồm, không tải một tệp theo yêu cầu, mà thay vào đó thay thế dòng #incoide, bằng nội dung của tệp. Các tệp được bao gồm không phải là 'tiêu đề' và #incoide không phải ở đầu tệp nhưng có thể ở bất cứ đâu, như trong lớp hoặc thậm chí là định nghĩa phương thức. Điều này có nghĩa là bạn có thể thực hiện mixin trong C ++ bằng cách viết một số phương thức trong một tệp và đưa nó vào mã của một lớp, chính xác là bạn sẽ làm gì trong ruby. Vì vậy, họ không đến mức đó, mặc dù đó thực sự không phải là một thông lệ trong C.
mb14

13
Câu trả lời này có thể có lợi bằng cách bao gồm các ví dụ.
Gấu Travis

12
Nhận xét của mb14 ngụ ý điều này, nhưng nó nói rõ: trái với những gì câu trả lời nói, yêu cầu không "chạy" một tệp, mà tải nó như thể nó là một phần của tệp chứa. Điều này có vẻ giống như nitpicking ngữ nghĩa nhưng thực sự nó là một sự khác biệt khá quan trọng.
Lonny Eachus 17/214

Giải thích tuyệt vời. Cảm ơn bạn đã lái xe về nhà với câu nói cuối cùng 'Thật kỳ lạ, yêu cầu của Ruby tương tự như bao gồm C, trong khi bao gồm của Ruby hầu như không có gì giống như C'.
ArtSabintsev

1
@GregSchmit: includetrong Ruby chỉ đơn giản là sự kế thừa. class C; include M endlàm cho Msiêu lớp của Cvà siêu lớp (cũ) của Csiêu lớp của M. Tôi không nghĩ rằng C includehoạt động thông qua thừa kế, tôi nghĩ đó là sự thay thế văn bản / từ vựng đơn giản.
Jörg W Mittag

100

Nếu bạn đang sử dụng một mô-đun, điều đó có nghĩa là bạn mang tất cả các phương thức vào lớp của mình. Nếu bạn extendlà một lớp với một mô-đun, điều đó có nghĩa là bạn "đưa vào" các phương thức của mô đun như các phương thức lớp . Nếu bạn includemột lớp học với một mô-đun, có nghĩa là bạn đang "đưa vào" phương pháp của mô-đun như ví dụ phương pháp.

VÍ DỤ:

 module A
   def say
     puts "this is module A"
   end
 end

 class B
   include A
 end

 class C
   extend A
 end

B.say => phương thức không xác định 'nói' cho B: Class

B.new.say => đây là mô-đun A

C.say => đây là mô-đun A

C.new.say => phương thức không xác định 'nói' cho C: Class


23
Tôi nghĩ rằng điều này không trả lời câu hỏi, nhưng đó là những gì tôi đang tìm kiếm =)
Ciro Santilli 冠状 病 六四 事件

2
Điều này không thực sự trả lời câu hỏi về sự khác biệt giữa requireincludelà gì.

94

Từ cuốn sách Metaprogramming Ruby,

Các require()phương pháp khá giống với load(), nhưng nó có nghĩa là cho mục đích khác. Bạn sử dụng load()để thực thi mã và bạn sử dụng require()để nhập thư viện.


73
Upvote vì không so sánh với ngôn ngữ khác trong câu trả lời của bạn :)
Stevo

Bỏ phiếu vì không cung cấp câu trả lời trong ngữ cảnh của câu hỏi: "Nếu tôi chỉ muốn sử dụng các phương thức từ một mô-đun trong lớp học của mình?"
benc

57
  • Ruby requiregiống như "bao gồm" trong các ngôn ngữ khác (chẳng hạn như C). Nó nói với Ruby rằng bạn muốn đưa vào nội dung của một tệp khác . Các cơ chế tương tự trong các ngôn ngữ khác là:

  • Ruby includelà một cơ chế kế thừa hướng đối tượng được sử dụng cho mixins .

Có một lời giải thích tốt ở đây :

[Câu trả lời] đơn giản là yêu cầu và bao gồm về cơ bản không liên quan.

"Yêu cầu" tương tự như bao gồm C, có thể gây nhầm lẫn cho người mới. (Một sự khác biệt đáng chú ý là người dân địa phương bên trong tệp yêu cầu "bốc hơi" khi yêu cầu được thực hiện.)

Ruby bao gồm không có gì giống như C bao gồm. Câu lệnh bao gồm "trộn trong" một mô-đun thành một lớp. Đó là một hình thức hạn chế của nhiều thừa kế . Một mô-đun đi kèm theo nghĩa đen ban cho một mối quan hệ "là-một" về điều bao gồm cả nó.

Nhấn mạnh thêm.


7

Bạn đã bao giờ thử requiremột mô-đun? Kết quả là gì? Thử xem:

MyModule = Module.new
require MyModule # see what happens

Mô-đun không thể được yêu cầu, chỉ bao gồm!


Khẳng định ở đây là không chính xác. Các mô-đun có thể được yêu cầu. Và bất cứ ai chạy mã trên sẽ thấy rằng họ nhận được kết quả tương tự ( TypeError) nếu từ Moduleđược đổi thành Class.
pjd

7

Từ lập trình Ruby 1.9

Chúng tôi sẽ đưa ra một vài điểm về tuyên bố bao gồm trước khi chúng tôi tiếp tục. Đầu tiên, nó không có gì để làm với các tập tin. Các lập trình viên C sử dụng một chỉ thị tiền xử lý có tên #include để chèn nội dung của một tệp vào tệp khác trong quá trình biên dịch. Câu lệnh Ruby bao gồm chỉ đơn giản là tham chiếu đến một mô-đun. Nếu mô-đun đó nằm trong một tệp riêng biệt, bạn phải sử dụng yêu cầu (hoặc người anh em ít sử dụng của nó, tải) để kéo tệp đó vào trước khi sử dụng bao gồm. Thứ hai, Ruby bao gồm không chỉ đơn giản là sao chép các phương thức cá thể của mô-đun vào lớp. Thay vào đó, nó tạo một tham chiếu từ lớp đến mô-đun đi kèm. Nếu nhiều lớp bao gồm mô-đun đó, tất cả chúng sẽ chỉ đến cùng một thứ. Nếu bạn thay đổi định nghĩa của một phương thức trong một mô-đun, ngay cả khi chương trình của bạn đang chạy,


3

Bao gồm Khi bạn Bao gồm một mô-đun vào lớp của bạn như được hiển thị bên dưới, như thể bạn đã lấy mã được xác định trong mô-đun và chèn nó vào trong lớp, nơi bạn 'bao gồm' nó. Nó cho phép hành vi 'mixin'. Ví dụ, nó được sử dụng để DRY mã của bạn để tránh trùng lặp, nếu có nhiều lớp sẽ cần cùng một mã trong mô-đun.

Tải Phương thức tải gần giống như phương thức yêu cầu ngoại trừ việc nó không theo dõi xem thư viện đó đã được tải hay chưa. Vì vậy, có thể tải thư viện nhiều lần và cả khi sử dụng phương thức tải, bạn phải chỉ định phần mở rộng của .Rbb của tên thư viện.

Yêu cầu Phương thức yêu cầu cho phép bạn tải thư viện và ngăn không cho nó tải nhiều lần. Phương thức yêu cầu sẽ trả về 'false' nếu bạn cố tải cùng một thư viện sau lần đầu tiên. Phương thức yêu cầu chỉ cần được sử dụng nếu thư viện bạn đang tải được xác định trong một tệp riêng, thường là trường hợp.

Bạn có thể thích http://ionrails.com/2009/09/19/ruby_Vquire-vs-load-vs-include-vs-extend/


3

Dưới đây là một số khác biệt cơ bản giữa yêu cầu và bao gồm:

Yêu cầu:

  1. Yêu cầu đọc tệp từ hệ thống tệp, phân tích cú pháp, lưu vào bộ nhớ và chạy nó ở một nơi nhất định, điều đó có nghĩa là nếu bạn thậm chí sẽ thay đổi bất cứ điều gì trong khi tập lệnh đang chạy thì thay đổi đó sẽ không phản ánh.
  2. Chúng tôi yêu cầu tệp theo tên, không phải theo tên mô-đun.
  3. Nó thường được sử dụng cho các thư viện và phần mở rộng.

Bao gồm:

  1. Khi bạn đưa một mô-đun vào lớp của mình, nó sẽ hoạt động như thể bạn lấy mã được xác định trong mô-đun của mình và chèn nó vào lớp của bạn.
  2. Chúng tôi bao gồm tên mô-đun, không phải tên tập tin.
  3. Nó thường được sử dụng để làm khô mã và loại bỏ trùng lặp trong mã.

2
require(name)

Nó sẽ trả về bolean đúng / sai

Tên được truyền dưới dạng tham số cho yêu cầu, ruby ​​sẽ cố gắng tìm tệp nguồn có tên đó trong đường dẫn tải của bạn. Phương thức yêu cầu sẽ trả về 'false' nếu bạn cố tải cùng một thư viện sau lần đầu tiên. Phương thức yêu cầu chỉ cần được sử dụng nếu thư viện bạn đang tải được xác định trong một tệp riêng. Vì vậy, nó theo dõi xem thư viện đó đã được tải hay chưa.

include module_name

Giả sử nếu bạn có một số phương thức mà bạn cần phải có trong hai lớp khác nhau. Sau đó, bạn không phải viết chúng trong cả hai lớp. Thay vào đó, những gì bạn có thể làm là, xác định nó trong mô-đun. Và sau đó bao gồm mô-đun này trong các lớp khác. Nó được cung cấp bởi Ruby chỉ để đảm bảo nguyên tắc DRY. Nó được sử dụng để DRY lên mã của bạn để tránh trùng lặp


2

Bao gồm

Khi bạn đưa includemột mô-đun vào lớp của mình, như thể bạn đã lấy mã được xác định trong mô-đun và chèn nó vào trong lớp, nơi bạn 'bao gồm' nó. Nó cho phép hành vi 'mixin'. Ví dụ, nó được sử dụng để DRY mã của bạn để tránh trùng lặp, nếu có nhiều lớp sẽ cần cùng một mã trong mô-đun.

module Log 
  def class_type
    "This class is of type: #{self.class}"
  end
end

class TestClass 
  include Log 
  # ... 
end

tc = TestClass.new.class_type # -> success
tc = TestClass.class_type # -> error

Yêu cầu

Phương thức yêu cầu cho phép bạn tải một thư viện và ngăn không cho nó được tải nhiều lần. Phương thức yêu cầu sẽ trả về 'false' nếu bạn cố tải cùng một thư viện sau lần đầu tiên. Phương thức yêu cầu chỉ cần được sử dụng nếu thư viện bạn đang tải được xác định trong một tệp riêng, thường là trường hợp.

Vì vậy, nó theo dõi xem thư viện đó đã được tải hay chưa. Bạn cũng không cần chỉ định phần mở rộng .rb của tên thư viện. Đây là một ví dụ về cách sử dụng yêu cầu. Đặt phương thức yêu cầu ở đầu tập tin .rb của bạn:

Tải

Phương thức tải gần giống như phương thức yêu cầu ngoại trừ việc nó không theo dõi xem thư viện đó đã được tải hay chưa. Vì vậy, có thể tải thư viện nhiều lần và cả khi sử dụng phương thức tải, bạn phải chỉ định phần mở rộng của .Rbb của tên thư viện.

Mở rộng

Khi sử dụng phương thức mở rộng thay vì bao gồm, bạn đang thêm các phương thức của mô đun làm phương thức lớp thay vì phương thức cá thể.

module Log 
  def class_type
    "This class is of type: #{self.class}"
  end
end

class TestClass 
  extend Log 
  # ... 
end

tc = TestClass.class_type

2

'Load'- chèn nội dung của tệp. (Phân tích tệp mỗi khi tệp được gọi)

'Yêu cầu'- chèn một tệp nội dung được phân tích cú pháp. (Tệp được phân tích cú pháp một lần và được lưu trong bộ nhớ)

'Bao gồm'- bao gồm mô-đun vào lớp và có thể sử dụng các phương thức bên trong mô-đun làm phương thức cá thể của lớp

'Extend'- bao gồm mô-đun vào lớp và có thể sử dụng các phương thức bên trong mô-đun làm phương thức lớp

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.