ความแตกต่างระหว่างการรวมและความต้องการในทับทิมคืออะไร?


465

คำถามของฉันคล้ายกับ "ความแตกต่างระหว่างการรวมและการขยายในทับทิมคืออะไร "

ความแตกต่างระหว่างrequireและincludeในทับทิมคืออะไร? ถ้าฉันเพียงต้องการใช้วิธีการจากโมดูลในชั้นเรียนของฉันฉันควรrequireหรือincludeไม่


1
สำหรับสิ่งที่คุ้มค่าที่นี่มีการเชื่อมโยงไปเอกสารชุมชนrequireและและยังเกี่ยวข้องinclude Module#append_features

คำตอบ:


543

ความแตกต่างระหว่าง "รวม" และ "ต้อง" ในทับทิมคืออะไร?

ตอบ:

การรวมและต้องการวิธีการทำสิ่งที่แตกต่างกันมาก

วิธีต้องการสิ่งที่รวมอยู่ในภาษาการเขียนโปรแกรมอื่น ๆ ส่วนใหญ่: เรียกใช้ไฟล์อื่น นอกจากนี้ยังติดตามสิ่งที่คุณต้องการในอดีตและไม่ต้องการไฟล์เดียวกันสองครั้ง หากต้องการเรียกใช้ไฟล์อื่นโดยไม่มีฟังก์ชั่นเพิ่มนี้คุณสามารถใช้วิธีโหลดได้

วิธีการรวมใช้วิธีการทั้งหมดจากโมดูลอื่นและรวมไว้ในโมดูลปัจจุบัน นี่คือสิ่งที่ระดับภาษาเมื่อเทียบกับสิ่งที่ระดับไฟล์เช่นเดียวกับต้องการ วิธีการรวมเป็นวิธีหลักในการ "ขยาย" เรียนกับโมดูลอื่น ๆ (มักจะเรียกว่าเป็นมิกซ์) ตัวอย่างเช่นถ้าคลาสของคุณกำหนดวิธีการ "แต่ละ" คุณสามารถรวมโมดูล mixin ที่นับได้และมันสามารถทำหน้าที่เป็นคอลเลกชัน สิ่งนี้อาจทำให้เกิดความสับสนเนื่องจากมีการใช้กริยารวมในภาษาอื่น

แหล่ง

requireดังนั้นถ้าคุณเพียงต้องการที่จะใช้โมดูลแทนที่จะขยายมันหรือผสมในแล้วคุณจะต้องการที่จะใช้

ผิดปกติพอทับทิมrequireจะคล้ายคลึงกับซีincludeขณะที่ทับทิมเกือบจะไม่มีอะไรเหมือนซีincludeinclude


45
ในความเป็นจริงของ C รวมถึงไม่โหลดไฟล์ตามที่ต้องการ แต่แทนที่ #include บรรทัดด้วยเนื้อหาของไฟล์แทน ไฟล์ที่รวมไม่จำเป็นต้องเป็น 'ส่วนหัว' และ #include ไม่จำเป็นต้องอยู่ที่จุดเริ่มต้นของไฟล์ แต่สามารถอยู่ที่ใดก็ได้เช่นในชั้นเรียนหรือแม้แต่การกำหนดวิธีการ ซึ่งหมายความว่าคุณสามารถทำ mixin ใน C ++ ได้โดยการเขียนวิธีการบางอย่างในไฟล์และรวมไว้ในรหัสของคลาสคุณจะต้องทำใน ruby ​​หรือไม่ ดังนั้นพวกเขาจึงอยู่ไม่ไกลถึงแม้ว่ามันจะไม่ใช่วิธีปฏิบัติทั่วไปในซี
mb14

13
คำตอบนี้อาจเป็นประโยชน์โดยรวมถึงตัวอย่าง
Travis Bear

12
ความคิดเห็นของ mb14 นัยนี้ แต่มันหมีระบุอย่างชัดเจน: สิ่งที่ตรงกันข้ามกับคำตอบที่บอกว่าต้องไม่ได้ "รัน" แฟ้ม แต่โหลดมันราวกับว่ามันเป็นส่วนหนึ่งของไฟล์ที่มี นี่อาจดูเหมือน nitpicking ความหมาย แต่จริงๆแล้วมันเป็นความแตกต่างที่สำคัญ
Lonny Eachus

คำอธิบายที่ดี ขอบคุณสำหรับการขับรถกลับบ้านด้วยคำแถลงสุดท้ายว่า 'ผิดปกติเพียงพอความต้องการของรูบี้นั้นคล้ายคลึงกับการรวมของ C ในขณะที่การรวมของรูบี้นั้นแทบจะไม่เหมือนกับการรวมของซีเลย'
ArtSabintsev

1
@GregSchmit: includeใน Ruby เป็นเพียงการสืบทอด class C; include M endทำให้Msuperclass ของCและ (อดีต) superclass ของCsuperclass Mของ ฉันไม่คิดว่าincludeงานของ C ผ่านการสืบทอดฉันคิดว่าเป็นการทดแทนข้อความ / ศัพท์แบบง่าย
Jörg W Mittag

100

หากคุณใช้โมดูลนั่นหมายความว่าคุณกำลังนำวิธีการทั้งหมดเข้าสู่ชั้นเรียนของคุณ หากคุณextendชั้นที่มีโมดูลที่หมายความว่าคุณกำลัง "นำ" วิธีการของโมดูลเป็นระดับวิธีการ หากคุณincludeชั้นที่มีโมดูลที่หมายความว่าคุณกำลัง "นำ" วิธีการของโมดูลเป็นเช่นวิธีการ

EX:

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

 class B
   include A
 end

 class C
   extend A
 end

B.say => วิธีที่ไม่ได้กำหนด 'พูด' สำหรับ B: Class

B.new.say => นี่คือโมดูล A

C.say => นี่คือโมดูล A

C.new.say => วิธีที่ไม่ได้กำหนด 'พูด' สำหรับ C: Class


23
ฉันคิดว่านี่ไม่ตอบคำถาม แต่มันคือสิ่งที่ฉันกำลังมองหา =)
Ciro Santilli 法轮功冠状病病六四事件法轮功

2
นี้ไม่จริงตอบคำถามในสิ่งที่แตกต่างระหว่างที่requireและincludeมี

94

จากหนังสือ Metaprogramming Ruby

require()วิธีการค่อนข้างคล้ายกับload()แต่มันมีความหมายสำหรับวัตถุประสงค์ที่แตกต่างกัน คุณใช้load()เพื่อเรียกใช้รหัสและคุณใช้ require()เพื่อนำเข้าไลบรารี


73
โหวตขึ้นที่ไม่ได้เปรียบเทียบกับภาษาอื่นในคำตอบของคุณ :)
Stevo

โหวตลงเพราะไม่ได้ให้คำตอบในบริบทของคำถาม: "ถ้าฉันต้องการใช้วิธีการจากโมดูลในชั้นเรียนของฉัน"
benc

57
  • Ruby requireเป็นเหมือน "รวม" ในภาษาอื่น ๆ (เช่น C) มันบอกทับทิมว่าคุณต้องการนำเนื้อหาของไฟล์อื่นมา กลไกที่คล้ายกันในภาษาอื่นคือ:

  • Ruby includeเป็นกลไกการสืบทอดเชิงวัตถุที่ใช้สำหรับมิกซ์อิน

มีคำอธิบายที่ดีที่นี่ :

[คำตอบง่ายๆ] คือความต้องการและการรวมนั้นไม่เกี่ยวข้องกันเป็นหลัก

"ต้องการ"คล้ายกับ C รวมซึ่งอาจทำให้เกิดความสับสนมือใหม่ (สิ่งหนึ่งที่น่าสังเกตคือความแตกต่างคือคนในไฟล์ "ระเหย" ที่ต้องการเมื่อทำเสร็จ)

การรวมทับทิมนั้นไม่เหมือนกับที่ C รวมอยู่ คำสั่ง include "มิกซ์ใน" โมดูลเข้ากับคลาส มันเป็นรูปแบบที่ จำกัด ของการสืบทอดหลายอย่าง โมดูลที่รวมอยู่นั้นมอบความสัมพันธ์แบบ "is-a" ให้กับสิ่งที่รวมอยู่ด้วย

เน้นการเพิ่ม


7

คุณเคยลองrequireโมดูลหรือไม่? ผลลัพธ์คืออะไร เพียงแค่พยายามที่:

MyModule = Module.new
require MyModule # see what happens

ไม่สามารถใช้โมดูลรวมอยู่ในนั้นเท่านั้น!


การยืนยันที่นี่ไม่ถูกต้อง สามารถเลือกโมดูลได้ และทุกคนที่ใช้รหัสดังกล่าวข้างต้นจะพบว่าพวกเขาได้รับผลเดียวกัน ( TypeError) ถ้าคำว่าจะเปลี่ยนไปModule Class
pjd

7

จากการเขียนโปรแกรม Ruby 1.9

เราจะทำสองสามจุดเกี่ยวกับคำสั่ง include ก่อนที่เราจะไปต่อ ก่อนอื่นไม่มีอะไรเกี่ยวข้องกับไฟล์ โปรแกรมเมอร์ C ใช้คำสั่ง preprocessor ชื่อ #include เพื่อแทรกเนื้อหาของไฟล์หนึ่งไปยังอีกไฟล์หนึ่งระหว่างการคอมไพล์ คำสั่ง Ruby include จะทำการอ้างอิงไปยังโมดูล หากโมดูลนั้นอยู่ในไฟล์แยกต่างหากคุณต้องใช้ต้องการ (หรือลูกพี่ลูกน้อง, โหลด) เพื่อลากไฟล์นั้นก่อนใช้งาน ประการที่สองการรวม Ruby ไม่เพียง แต่คัดลอกวิธีการของโมดูลไปยังคลาส แต่จะทำการอ้างอิงจากคลาสไปยังโมดูลที่รวมไว้ หากหลายคลาสมีโมดูลนั้นพวกเขาทั้งหมดจะชี้ไปที่สิ่งเดียวกัน หากคุณเปลี่ยนคำจำกัดความของวิธีการภายในโมดูลแม้ในขณะที่โปรแกรมของคุณกำลังทำงาน


3

รวมเมื่อคุณรวมโมดูลเข้าไปในคลาสของคุณดังแสดงด้านล่างราวกับว่าคุณได้ใส่รหัสที่กำหนดไว้ในโมดูลและใส่เข้าไปในคลาสที่คุณ 'รวม' ไว้ จะช่วยให้พฤติกรรม 'mixin' มันใช้เพื่อเพิ่มโค้ดของคุณเพื่อหลีกเลี่ยงการทำซ้ำเช่นถ้ามีหลายคลาสที่จะต้องใช้รหัสเดียวกันภายในโมดูล

โหลดวิธีโหลดนั้นคล้ายกับวิธีต้องการยกเว้นว่าจะไม่ติดตามว่ามีการโหลดไลบรารีหรือไม่ ดังนั้นจึงเป็นไปได้ที่จะโหลดไลบรารีหลาย ๆ ครั้งและเมื่อใช้วิธีการโหลดคุณต้องระบุนามสกุล“ .rb” ของชื่อไฟล์ไลบรารี

ต้องการวิธีการต้องการให้คุณโหลดไลบรารีและป้องกันไม่ให้โหลดมากกว่าหนึ่งครั้ง เมธอด require จะส่งคืน 'false' หากคุณพยายามโหลดไลบรารี่เดียวกันหลังจากครั้งแรก เมธอด need จำเป็นต้องใช้เฉพาะถ้าไลบรารีที่คุณกำลังโหลดถูกกำหนดในไฟล์แยกต่างหากซึ่งโดยปกติจะเป็นตัวพิมพ์เล็ก

คุณสามารถชอบ http://ionrails.com/2009/09/19/ruby_require-vs-load-vs-include-vs-extend/


3

ด้านล่างมีความแตกต่างพื้นฐานเล็กน้อยระหว่างความต้องการและการรวม:

จำเป็นต้อง:

  1. จำเป็นต้องอ่านไฟล์จากระบบไฟล์แยกวิเคราะห์บันทึกในหน่วยความจำและรันไฟล์ในสถานที่ที่กำหนดซึ่งหมายความว่าถ้าคุณจะเปลี่ยนแปลงอะไรก็ตามในขณะที่สคริปต์ทำงานมากกว่าการเปลี่ยนแปลงนั้นจะไม่สะท้อน
  2. เราต้องการไฟล์ตามชื่อไม่ใช่ตามชื่อโมดูล
  3. โดยทั่วไปจะใช้สำหรับไลบรารีและส่วนขยาย

รวมถึง:

  1. เมื่อคุณรวมโมดูลเข้าไปในชั้นเรียนของคุณมันจะทำงานเหมือนว่าคุณเอารหัสที่กำหนดไว้ในโมดูลของคุณและใส่เข้าไปในชั้นเรียนของคุณ
  2. เรารวมชื่อโมดูลไม่ใช่ชื่อไฟล์
  3. โดยทั่วไปจะใช้ในการทำให้รหัสแห้งและเพื่อลบการทำซ้ำในรหัส

2
require(name)

มันจะคืนค่าโบลีนจริง / เท็จ

ชื่อที่ถูกส่งผ่านเป็นพารามิเตอร์ไปยังที่ต้องการทับทิมจะพยายามหาไฟล์ต้นฉบับที่มีชื่อนั้นในเส้นทางโหลดของคุณ เมธอด require จะส่งคืน 'false' หากคุณพยายามโหลดไลบรารี่เดียวกันหลังจากครั้งแรก เมธอด need จำเป็นต้องใช้เฉพาะถ้าไลบรารีที่คุณกำลังโหลดถูกกำหนดในไฟล์แยกต่างหาก ดังนั้นจึงติดตามว่ามีการโหลดไลบรารีนั้นหรือไม่

include module_name

สมมติว่าคุณมีวิธีการบางอย่างที่คุณจำเป็นต้องมีในสองชั้นที่แตกต่างกัน จากนั้นคุณไม่ต้องเขียนมันทั้งสองคลาส สิ่งที่คุณสามารถทำได้คือกำหนดไว้ในโมดูล แล้วรวมโมดูลนี้ในชั้นเรียนอื่น ๆ จัดทำโดย Ruby เพื่อให้มั่นใจถึงหลักการของ DRY ใช้เพื่อเพิ่มรหัสของคุณเพื่อหลีกเลี่ยงการทำซ้ำ


2

ประกอบด้วย

เมื่อคุณincludeใส่โมดูลในชั้นเรียนของคุณมันก็เหมือนกับว่าคุณเอารหัสที่กำหนดไว้ในโมดูลและใส่เข้าไปในชั้นเรียนที่คุณรวมไว้ จะช่วยให้พฤติกรรม 'mixin' มันใช้เพื่อเพิ่มโค้ดของคุณเพื่อหลีกเลี่ยงการทำซ้ำเช่นถ้ามีหลายคลาสที่จะต้องใช้รหัสเดียวกันภายในโมดูล

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

จำเป็นต้อง

เมธอด require อนุญาตให้คุณโหลดไลบรารีและป้องกันไม่ให้โหลดมากกว่าหนึ่งครั้ง เมธอด require จะส่งคืน 'false' หากคุณพยายามโหลดไลบรารี่เดียวกันหลังจากครั้งแรก เมธอด need จำเป็นต้องใช้เฉพาะถ้าไลบรารีที่คุณกำลังโหลดถูกกำหนดในไฟล์แยกต่างหากซึ่งโดยปกติจะเป็นตัวพิมพ์เล็ก

ดังนั้นจึงติดตามว่ามีการโหลดไลบรารีนั้นหรือไม่ คุณไม่จำเป็นต้องระบุส่วนขยาย“ .rb” ของชื่อไฟล์ไลบรารี นี่คือตัวอย่างวิธีการใช้ที่ต้องการ วางเมธอด need ที่ด้านบนสุดของไฟล์“ .rb” ของคุณ:

ภาระ

วิธีการโหลดนั้นเกือบจะเหมือนวิธีที่ต้องการยกเว้นว่ามันจะไม่ติดตามว่ามีการโหลดไลบรารีนั้นหรือไม่ ดังนั้นจึงเป็นไปได้ที่จะโหลดไลบรารีหลาย ๆ ครั้งและเมื่อใช้วิธีการโหลดคุณต้องระบุนามสกุล“ .rb” ของชื่อไฟล์ไลบรารี

ต่ออายุ

เมื่อใช้วิธีการขยายแทนการรวมคุณจะเพิ่มวิธีการโมดูลเป็นวิธีการเรียนแทนวิธีการเช่น

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

class TestClass 
  extend Log 
  # ... 
end

tc = TestClass.class_type

2

'โหลด' - แทรกเนื้อหาของไฟล์ (แยกวิเคราะห์ไฟล์ทุกครั้งที่มีการเรียกไฟล์)

'Require'- แทรกเนื้อหาแยกไฟล์ (แยกวิเคราะห์ไฟล์ครั้งเดียวและเก็บไว้ในหน่วยความจำ)

'Include'- รวมโมดูลเข้าไปในคลาสและสามารถใช้เมธอดภายในโมดูลเป็นวิธีอินสแตนซ์ของคลาส

'Extend' - รวมโมดูลเข้าไปในคลาสและสามารถใช้วิธีการภายในโมดูลเป็นวิธีการเรียน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.