คำสั่งกรณีที่มีหลายค่าในแต่ละบล็อก 'เมื่อ'


314

วิธีที่ดีที่สุดที่ฉันสามารถอธิบายสิ่งที่ฉันกำลังมองหาคือการแสดงรหัสที่ล้มเหลวที่ฉันได้ลองไปแล้ว:

case car
  when ['honda', 'acura'].include?(car)
    # code
  when 'toyota' || 'lexus'
    # code
end

ฉันมีประมาณ 4 หรือ 5 ที่แตกต่างกันwhenในสถานการณ์ที่ควรจะเรียกโดยประมาณ 50 carค่าที่เป็นไปแตกต่างกันของ มีวิธีทำเช่นนี้กับcaseบล็อกหรือฉันควรลองifบล็อกขนาดใหญ่หรือไม่?

คำตอบ:


669

ในcaseคำสั่ง a ,จะเทียบเท่ากับ||ในifคำสั่ง

case car
   when 'toyota', 'lexus'
      # code
end

บางสิ่งอื่น ๆ ที่คุณสามารถทำได้ด้วยคำสั่งกรณีทับทิม


1
ลิงก์นี้มีข้อมูลสรุปที่ดีขึ้นของคำสั่ง case ใน Ruby (และรวมถึงตัวอย่างของไวยากรณ์ regexp และ splat ด้วย)
rsenna

ฉันไม่รู้ว่าทำไม แต่สถานการณ์ที่แปลกประหลาดนี้เกิดขึ้น: เมื่อฉันเขียนสิ่งนี้: when "toyota", "lexus"ฉันจะได้รับ: unexpected tSTRING_BEG, expecting keyword_do or '{' or '(' (SyntaxError). อย่างไรก็ตามเมื่อฉันเขียนสิ่งนี้: when "toyota","lexus"มันใช้งานได้ ข้อแตกต่างเพียงอย่างเดียวคือช่องว่างหลังจากเครื่องหมายจุลภาค
Furkan Ayhan

@ FurkanAyhan มันแปลกมาก ฉันไปข้างหน้าและทดสอบรหัสเพื่อให้แน่ใจและใช้งานได้ ฉันเดาว่ามีบางอย่างเกิดขึ้นในรหัสของคุณที่ทำให้เกิดข้อผิดพลาดเช่นนั้น เป็นไปได้ไหมที่คุณลืมที่จะปิดสายอักขระที่อื่นหรืออะไรทำนองนั้น?
Charles Caldwell

1
มันใช้งานได้ดี แต่เนื่องจากทับทิมให้ความสำคัญกับความง่ายของโปรแกรมเมอร์ฉันจึงสงสัยว่าทำไมจึงไม่สนับสนุนมาตรฐาน || หรือ 'หรือ' นี่คือความสับสน
Zia Ul Rehman Mughal

2
Ruby ไม่สนับสนุนorหรือ||ที่นี่เพราะการwhenใช้ชุดของนิพจน์คั่นด้วยเครื่องหมายจุลภาคทางด้านขวาไม่ใช่ตัวระบุเดียว ด้วยเหตุนี้ถ้าคุณมีwhen a or bมันไม่ชัดเจนว่านี่จะต้องถูกนำมาใช้เทียบเท่า when a, bหรือwhen (a or b)หลังซึ่งประเมินการแสดงออกa or bครั้งแรกก่อนที่จะโยนลงในเวลา มันน่าแปลกใจมากขึ้นและง่ายต่อการจัดการสำหรับภาษาที่มีโทเค็นที่เปลี่ยนพฤติกรรมตามบริบทแล้วคุณจะไม่สามารถใช้การorแสดงออกที่แท้จริงทางด้านขวาของเวลา
Taywee

99

คุณอาจใช้ประโยชน์จาก "splat" ของรูบี้หรือไวยากรณ์ที่แบนราบ

สิ่งนี้ทำให้whenประโยคที่รกเกินไป- คุณมีค่าประมาณ 10 ค่าที่จะทดสอบต่อสาขาถ้าฉันเข้าใจถูกต้อง - สามารถอ่านได้ในความคิดของฉัน นอกจากนี้คุณสามารถปรับเปลี่ยนค่าเพื่อทดสอบที่รันไทม์ ตัวอย่างเช่น:

honda  = ['honda', 'acura', 'civic', 'element', 'fit', ...]
toyota = ['toyota', 'lexus', 'tercel', 'rx', 'yaris', ...]
...

if include_concept_cars
  honda += ['ev-ster', 'concept c', 'concept s', ...]
  ...
end

case car
when *toyota
  # Do something for Toyota cars
when *honda
  # Do something for Honda cars
...
end

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


นี่คือสิ่งที่ฉันลงเอยด้วยการใช้แม้ว่าฉันจะรู้สึกไม่ดีที่จะลบเครื่องหมายของใครบางคน: D
นิค

วิธีแก้ปัญหาที่ยอดเยี่ยมสำหรับwhenสายยาว ขอบคุณสำหรับการแบ่งปัน.
Pistos

0

อีกวิธีที่ดีในการวางตรรกะของคุณลงในข้อมูลคือสิ่งนี้

# Initialization.
CAR_TYPES = {
  foo_type: ['honda', 'acura', 'mercedes'],
  bar_type: ['toyota', 'lexus']
  # More...
}
@type_for_name = {}
CAR_TYPES.each { |type, names| names.each { |name| @type_for_name[type] = name } }

case @type_for_name[car]
when :foo_type
  # do foo things
when :bar_type
  # do bar things
end

ฉันไม่ได้ตั้งใจจะหยาบคาย แต่ฉัน downvoted เพราะมันมีประสิทธิภาพน้อยกว่าทั้งเวลาและสถานที่ นอกจากนี้ยังซับซ้อนและอ่านน้อยกว่าคำตอบอีกสองข้อ อะไรคือประโยชน์ของการใช้วิธีนี้?
นิค

มันทำให้การจำแนกทั้งหมดของคุณเป็นวัตถุเดียว ตอนนี้คุณสามารถทำสิ่งต่าง ๆ กับวัตถุนั้นเช่นทำให้เป็นอันดับและส่งไปให้คนอื่นเพื่ออธิบายตรรกะของคุณหรือเก็บไว้ในฐานข้อมูลและอนุญาตให้ผู้ใช้แก้ไขได้ (ตรรกะจะเปลี่ยนไปในไม่ช้าเมื่อรถรุ่นใหม่ออกมาใช่มั้ย) คุณอาจค้นหา "ขับเคลื่อนด้วยตาราง"
Hew Wolff

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