ทับทิม: kind_of? เทียบกับ instance_of? เทียบกับ is_a?


487

อะไรคือความแตกต่าง? เมื่อใดที่ฉันควรใช้ ทำไมถึงมีหลายคน?


18
ทำไมทั้งสองis_a?และkind_of?มีอยู่: ฉันคิดว่ามันเป็นส่วนหนึ่งของปรัชญาการออกแบบของรูบี้ Python จะบอกว่าควรจะมีวิธีเดียวเท่านั้นที่จะทำอะไรบางอย่าง; Ruby มักจะมีวิธีการตรงกันดังนั้นคุณสามารถใช้วิธีที่ดีกว่า มันเป็นเรื่องของการตั้งค่า ส่วนหนึ่งอาจเป็นเพราะอิทธิพลของญี่ปุ่น: ฉันบอกว่าพวกเขาจะใช้คำที่แตกต่างกันสำหรับหมายเลขเดียวกันขึ้นอยู่กับประโยคเพื่อให้เสียงดีขึ้น Matz อาจนำความคิดนั้นไปใช้ในการออกแบบภาษาของเขา
Nathan Long

@NathanLong ฉันไม่คิดว่าเคาน์เตอร์ญี่ปุ่นมีส่วนเกี่ยวข้องกับมันมากนัก ทุกภาษามีข้อตกลงบางอย่างและคุณไม่สามารถทดแทนตัวนับหนึ่งได้อีกส่วนใหญ่ (เช่นคุณไม่สามารถใช้ตัวนับรูปทรงกระบอกสำหรับวัตถุทรงแบนได้ แต่มันผิด) และมันเกี่ยวข้องกับซีแมนทิกส์มากกว่าความไพเราะ
Casey

คำตอบ:


621

kind_of?และis_a?มีความหมายเหมือนกัน

instance_of?จะแตกต่างจากอีกสองที่ว่ามันจะส่งกลับเฉพาะtrueถ้าวัตถุเป็นตัวอย่างของชั้นเรียนที่แน่นอนว่าไม่ใช่คลาสย่อย

ตัวอย่าง:

  • "hello".is_a? Objectและ"hello".kind_of? Objectการกลับมาtrueเพราะ"hello"เป็นStringและStringเป็น subclass Objectของ
  • อย่างไรก็ตามผลตอบแทน"hello".instance_of? Objectfalse

77
บางครั้งมันก็อ่านได้ดีขึ้น คิด@honda.kind_of? Carและ@person.is_a? Administratorรูบี้เกี่ยวกับสุนทรียภาพทั้งหมด ในความเป็นจริงให้สังเกตข้อผิดพลาดทางไวยากรณ์ ... ด้วยการสนับสนุนที่ใช้งานได้คุณสามารถเขียน:) @person.is_an? Administrator... ที่อาจทำให้มันกลายเป็นแกนทับทิมในตอนนี้จริง ๆ แล้ว
rfunduk

2
เฮ้นั่นเป็นเหตุผลที่น่าสนใจ คุณสามารถทำลายสิ่งนี้ได้ไหม เช่นคุณสามารถแทนที่kind_of?แต่ไม่is_a??
Claudiu

3
@thenduks is_an?ไม่ได้อยู่ใน ruby-1.9.2-p0 @ Claudiu ไม่ เป็นเพียงนามแฝงของis_a? kind_of?ทั้งสองวิธีเรียกใช้ฟังก์ชัน c เดียวกัน, rb_obj_is_kind_of.
ma11hew28

9
@Matt: คุณสามารถลบล้างนามแฝงได้โดยไม่ต้องลบล้างฟังก์ชั่น aliased ดังนั้นใช่คุณสามารถแทนที่โดยไม่ต้องเอาชนะkind_of? is_a?
sepp2k

4
is_an?วิธีActiceSupport นี้อยู่ที่ไหน! มันไม่ได้อยู่ในรุ่น Rails ปัจจุบันและฉันไม่สามารถหาอะไรเลยใน google เกี่ยวกับเรื่องนี้ที่เลิกใช้แล้ว
ทอมลอร์ด

22

อะไรคือความแตกต่าง?

จากเอกสาร:

- ( บูลีน )instance_of?(class)
ส่งคืนtrueถ้าobjเป็นอินสแตนซ์ของคลาสที่กำหนด

และ:

- ( บูลีน ) is_a?(class)
- ( บูลีน )kind_of?(class)
ผลตอบแทนtrueถ้าclassเป็นชั้นของobjหรือถ้าclassเป็นหนึ่งใน superclasses ของหรือโมดูลรวมอยู่ในobjobj

หากไม่มีความชัดเจนก็จะดีจะรู้ว่าสิ่งที่ว่าเป็นที่ชัดเจนเพื่อให้เอกสารสามารถปรับปรุง

เมื่อใดที่ฉันควรใช้

ไม่เคย ใช้ polymorphism แทน

ทำไมถึงมีหลายคน?

ฉันไม่เรียกสองคนว่า "หลายคน" มีสองคนเพราะพวกเขาทำสองสิ่งที่แตกต่างกัน


3
ฉันคิดว่าความสับสนของฉันคือมี 3 และ 2 นั้นทำสิ่งเดียวกันและมีชื่อแตกต่างกัน เกี่ยวกับการใช้ polymorphism - ฉันเห็นด้วย แต่ไลบรารี่มาตรฐานของทับทิมเต็มไปด้วยการใช้งานเหล่านี้
Claudiu

4
คุณหมายถึงอะไรโดย polymorphism มันเหมือนกับการพิมพ์เป็ดหรือเปล่า?
Andrew Grimm

2
ใช่พวกเขาเหมือนกัน การพิมพ์เป็ดเป็นรูปแบบหนึ่งของความหลากหลาย
SpaceGhost

3
มันมักจะดีกว่าที่จะทำ polymorphism ใช่ แต่มีหลายกรณีที่คุณต้องการทราบว่าคุณมีคลาสที่เฉพาะเจาะจงเช่นเมื่อคุณจัดการกับไฟล์
Automatico

6

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

แน่นอนว่ามันไม่สามารถใช้ได้เสมอไปดังนั้นจึงยังมีความเป็นไปได้ที่จะถามเกี่ยวกับความเข้าใจแบบ "ประเภท" ซึ่งเป็นคลาสหรือคลาสพื้นฐานโดยใช้วิธีการที่คุณถาม


5
ขึ้นอยู่กับสถานการณ์ ทั้งความคิดเห็นและบล็อกอาจตอบสนองต่อ created_at ในสถานการณ์เช่นนี้คืออะไร IMHO เหมาะสมกว่า
penkovsky

ไม่สมเหตุสมผลหากคุณต้องการแยกความคิดเห็นและวัตถุบล็อกจากกันและกันคุณจะไม่ใช้ created_at ในการทำเช่นนั้น แต่นั่นไม่ได้ขัดขวางว่าคุณสามารถเขียนวิธีการที่ใช้วัตถุที่ตอบสนองต่อ created_at หากไม่ต้องการสิ่งอื่นใดในการทำงานคุณสามารถใช้งานได้อย่างปลอดภัยบนความคิดเห็นหรือบล็อกหรือรูปแบบ ActiveRecord อื่น ๆ
Kingdon

3

ฉันจะไม่เรียกสองอย่าง ( is_a?และkind_of?เป็นนามแฝงของวิธีการเดียวกัน) แต่ถ้าคุณต้องการดูความเป็นไปได้มากขึ้นให้หันความสนใจไปที่#classวิธีการ:

A = Class.new
B = Class.new A

a, b = A.new, B.new
b.class < A # true - means that b.class is a subclass of A
a.class < B # false - means that a.class is not a subclass of A
# Another possibility: Use #ancestors
b.class.ancestors.include? A # true - means that b.class has A among its ancestors
a.class.ancestors.include? B # false - means that B is not an ancestor of a.class

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