ฉันจะใช้โอเปอเรเตอร์ที่มีเงื่อนไขได้อย่างไร (? :) ใน Ruby


303

ตัวดำเนินการตามเงื่อนไข ( ? :) ใช้งานใน Ruby อย่างไร

เช่นนี้ถูกต้องหรือไม่

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>

1
ใช่ฉันคิดว่า แต่ฉันก็คิดว่าคุณสามารถทำได้โดย: question=question[0,20] ถ้ามันเล็กกว่า 20 มันจะไม่เปลี่ยนเลย
DGM

ฉันต้องเพิ่ม '... ' ถ้าความยาวมากกว่า 20
Mithun Sreedharan

1
ระวังการตัดสายที่คอลัมน์ที่กำหนดอย่างสุ่ม ๆ คุณสามารถลงเอยคำกลางคันแล้วต่อท้าย elipsis ('... ') ซึ่งดูไม่ดี ให้มองหาเครื่องหมายวรรคตอนหรือช่องว่างที่อยู่ใกล้เคียงแทนและตัดทอนที่นั่นแทน หากไม่มีจุดแตกหักที่ดีกว่าในบริเวณใกล้เคียงหากคุณตัดทอนคำกลาง
Tin Man

คำตอบ:


496

มันเป็นตัวดำเนินการที่ประกอบไปด้วยสามตัวและทำงานเหมือนใน C (ไม่ต้องใช้วงเล็บ) มันเป็นสำนวนที่ใช้งานได้:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

อย่างไรก็ตามใน Ruby ifยังเป็นนิพจน์ดังนี้: if a then b else c end=== a ? b : cยกเว้นประเด็นที่สำคัญกว่า ทั้งคู่เป็นการแสดงออก

ตัวอย่าง:

puts (if 1 then 2 else 3 end) # => 2

puts 1 ? 2 : 3                # => 2

x = if 1 then 2 else 3 end
puts x                        # => 2

โปรดทราบว่าในกรณีแรกต้องใช้วงเล็บ (มิฉะนั้น Ruby จะสับสนเพราะคิดว่ามันเป็นputs if 1ขยะพิเศษหลังจากนั้น) แต่ไม่จำเป็นต้องใช้ในกรณีสุดท้ายเนื่องจากปัญหาดังกล่าวไม่เกิดขึ้น

คุณสามารถใช้แบบฟอร์ม "long-if" เพื่อให้สามารถอ่านได้หลายบรรทัด:

question = if question.size > 20 then
  question.slice(0, 20) + "..."
else 
  question
end

ใส่ 0 2: 3 ก็ให้ 2 ด้วย ทำไมถึงเป็นอย่างนั้น?
X_Trust

18
@X_Trust ในทับทิมค่าเพียง falsy มีและnil falseไม่ปกติแน่นอน
Kroltan

35
puts true ? "true" : "false"
=> "true"


puts false ? "true" : "false"
=> "false"

Terse แต่อธิบายว่ามันทำอะไร
ชายดีบุก

4
แก้ไขเล็ก ๆputs (true ? "true" : "false")ด้วยวงเล็บ มิฉะนั้นคำสั่งของการดำเนินการจะไม่ชัดเจน เมื่อฉันอ่านสิ่งนี้ครั้งแรกฉันรู้สึกสับสนเมื่อฉันอ่านตามที่ (puts true) ? "true" : "false"คาดไว้ว่าputsจะส่งคืนบูลีนซึ่งกลายเป็นค่าสตริง
Fresheyeball

26

การใช้ ERB ของคุณแนะนำว่าคุณอยู่ใน Rails ถ้าเป็นเช่นนั้นให้พิจารณาtruncateผู้ช่วยที่มีอยู่แล้วซึ่งจะทำงานให้คุณ:

<% question = truncate(question, :length=>30) %>

มันเยี่ยมมาก! สิ่งที่ฉันอยากจะทำ !!
Mithun Sreedharan

11
นี่เป็นเวลาหลายปีแล้ว แต่ฉันก็ประทับใจกับคำตอบนี้มากเพราะมันกระโดดผ่านทุกแง่มุมของการสร้างประโยคและเดินตรงไปยังสิ่งที่ผู้ถามพยายามทำให้สำเร็จ
Mike Buckbee

2
+1 แต่ erb ไม่ได้แปลว่าราง (Sinatra, ERB แบบสแตนด์อโลนเป็นต้น)
Fox Wilson

17

@pst ให้คำตอบที่ดี แต่ฉันอยากจะพูดถึงว่าใน Ruby ผู้ประกอบการที่ประกอบไปด้วยสามบรรทัดถูกเขียนในประโยคเพื่อให้ถูกต้องทางไวยากรณ์ซึ่งแตกต่างจาก Perl และ C ที่เราสามารถเขียนได้หลายบรรทัด:

(true) ? 1 : 0

โดยปกติ Ruby จะทำให้เกิดข้อผิดพลาดหากคุณพยายามแยกมันออกเป็นหลาย ๆ บรรทัด แต่คุณสามารถใช้\สัญลักษณ์ต่อเนื่องของบรรทัดที่ท้ายบรรทัดและ Ruby จะมีความสุข:

(true)   \
  ? 1    \
  : 0

นี่เป็นตัวอย่างง่ายๆ แต่มันมีประโยชน์มากเมื่อต้องจัดการกับบรรทัดที่ยาวกว่าเนื่องจากมันจะช่วยให้โค้ดถูกวางไว้อย่างดี

นอกจากนี้ยังเป็นไปได้ที่จะใช้ ternary ที่ไม่มีตัวอักษรต่อเนื่องของบรรทัดโดยวางโอเปอเรเตอร์ไว้ในบรรทัด แต่ฉันไม่ชอบหรือแนะนำ:

(true) ?
  1 :
  0

ฉันคิดว่าสิ่งนี้นำไปสู่การอ่านโค้ดที่ยากมากเนื่องจากการทดสอบตามเงื่อนไขและ / หรือผลลัพธ์นั้นยาวขึ้น

ฉันได้อ่านความคิดเห็นที่บอกว่าไม่ควรใช้ผู้ประกอบการที่ประกอบไปด้วยความสับสน แต่นั่นเป็นเหตุผลที่ไม่ดีที่จะไม่ใช้อะไร ด้วยตรรกะเดียวกันเราไม่ควรใช้นิพจน์ทั่วไปตัวดำเนินการช่วง (' ..' และรูปแบบ "ฟลิปฟล็อป" ที่ดูเหมือนจะไม่รู้จัก) มีประสิทธิภาพเมื่อใช้อย่างถูกต้องดังนั้นเราควรเรียนรู้การใช้อย่างถูกต้อง


ทำไมคุณใส่วงเล็บรอบtrue?

พิจารณาตัวอย่างของ OP:

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>

การห่อการทดสอบตามเงื่อนไขช่วยให้อ่านง่ายขึ้นเพราะแยกการทดสอบออกเป็นภาพ:

<% question = (question.size > 20) ? question.question.slice(0, 20)+"..." : question.question %>

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

<% question = (question.size > 20) ? question.question.slice(0, 20) + "..." \
                                   : question.question 
%>

หรือเขียนเพิ่มเติมมากกว่าสำนวน:

<% question = if (question.size > 20)
                question.question.slice(0, 20) + "..."
              else 
                question.question 
              end
%>

เป็นเรื่องง่ายที่จะโต้แย้งว่าการอ่านนั้นมีความเลวquestion.questionเช่นกัน


1
หากใช้หลายบรรทัดทำไมไม่ใช้เพียงถ้า ... อื่น ... สิ้นสุด
Wayne Conrad

1
เนื่องจากทำงานกับ Perl และ C หลายปีเกินไป ฉันใช้อย่างใดอย่างหนึ่งขึ้นอยู่กับสถานการณ์และดูว่าชัดเจนกว่าอีกหรือไม่ บางครั้งถ้า / อื่น verbose เกินไปบางครั้ง?: น่าเกลียด
มนุษย์ดีบุก

1
@WayneConrad หากมีปัญหาอย่างน้อยหนึ่งข้อที่อธิบายไว้ในคำตอบนี้: stackoverflow.com/a/4252945/2597260เปรียบเทียบวิธีการใช้ multiline if / ternary operator หลายวิธี: gist.github.com/nedzadarek/0f9f99755d42bad10c30
Darek Nędza

ทำไมคุณใส่วงเล็บรอบtrue?
Zac

1
เพราะtrueเป็นจริงนั่งอยู่ในสำหรับสิ่งที่จะแสดงออกที่ประเมินหรือtrue falseเป็นการดีกว่าที่จะกำหนดขอบเขตที่มองเห็นได้เนื่องจากข้อความประกอบไปด้วยส่วนสั้นสามารถเปลี่ยนเป็นเสียงรบกวนทางสายตาได้อย่างรวดเร็วลดความสามารถในการอ่านที่มีผลต่อการบำรุงรักษา
มนุษย์ดีบุก

3

ตัวอย่างง่าย ๆ ที่โอเปอเรเตอร์ตรวจสอบว่ารหัสผู้เล่นเป็น 1 และตั้งรหัสศัตรูขึ้นอยู่กับผลลัพธ์

player_id=1
....
player_id==1? enemy_id=2 : enemy_id=1
# => enemy=2

และฉันพบโพสต์เกี่ยวกับหัวข้อที่ดูเหมือนว่าค่อนข้างเป็นประโยชน์


4
ทำไมenemy_id = player_id == 1 ? 2 : 1ล่ะ
Aaron Blenkush

1
@AaronBlenkush ขอบคุณสำหรับการป้อนข้อมูลที่สง่างาม ผมยังคงอยู่ในระดับ Noob อาจจะเป็นเหตุผลที่มัน :)
devwanderer


0

วิธีที่ง่ายที่สุด:

param_a = 1
param_b = 2

result = param_a === param_b ? 'Same!' : 'Not same!'

เนื่องจากparam_aไม่เท่ากับparam_bแล้วresultค่าของจะเป็นNot same!

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