Làm cách nào để sử dụng toán tử điều kiện (? :) trong Ruby?


303

Toán tử điều kiện ( ? :) được sử dụng trong Ruby như thế nào?

Ví dụ, điều này có đúng không?

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

1
vâng, tôi nghĩ vậy, nhưng tôi cũng nghĩ bạn có thể hoàn thành điều đó bằng cách: question=question[0,20] Nếu nó nhỏ hơn 20, nó sẽ không thay đổi nó.
DGM

tôi cũng cần thêm '...' nếu chiều dài lớn hơn 20
Mithun Sreedharan

1
Hãy cẩn thận cắt một cách mù quáng một dòng tại một cột nhất định. Cuối cùng, bạn có thể cắt một từ giữa chừng sau đó nối thêm phần elipsis ('...'), trông có vẻ tệ. Thay vào đó, hãy tìm một ký tự dấu chấm hoặc khoảng trắng gần đó và cắt bớt ở đó. Chỉ khi không có điểm phá vỡ tốt hơn gần đó thì bạn mới nên cắt từ giữa.
Tin Man

Câu trả lời:


496

Nó là toán tử ternary và nó hoạt động như trong C (không yêu cầu dấu ngoặc đơn). Đó là một biểu thức hoạt động như:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

Tuy nhiên, trong Ruby, ifcũng là một biểu thức vì vậy: if a then b else c end=== a ? b : c, ngoại trừ các vấn đề ưu tiên. Cả hai đều là biểu thức.

Ví dụ:

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

Lưu ý rằng trong trường hợp đầu tiên, bắt buộc phải có dấu ngoặc đơn (nếu không thì Ruby bị nhầm lẫn vì nó nghĩ rằng nó puts if 1có thêm một số rác sau đó), nhưng chúng không được yêu cầu trong trường hợp cuối cùng vì vấn đề đã nói không phát sinh.

Bạn có thể sử dụng biểu mẫu "long-if" để dễ đọc trên nhiều dòng:

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

Đặt 0? 2: 3 cũng cho kết quả là 2. Tại sao vậy?
X_Trust

18
@X_Trust Trong Ruby, các giá trị giả chỉ là nilfalse. Thật ra không bình thường lắm.
Kroltan

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


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

Terse nhưng giải thích những gì nó làm.
Tin Man

4
Chỉnh sửa nhỏ puts (true ? "true" : "false")với dấu ngoặc đơn. Nếu không thì thứ tự hoạt động không rõ ràng. Khi tôi lần đầu tiên đọc nó, tôi đã bối rối khi tôi đọc nó và (puts true) ? "true" : "false"sau đó dự kiến ​​sẽ putstrả về boolean mà sau đó trở thành giá trị chuỗi.
Fresheyeball

26

Việc bạn sử dụng ERB cho thấy bạn đang ở trong Rails. Nếu vậy, hãy xem xét truncate, một người trợ giúp tích hợp sẽ thực hiện công việc cho bạn:

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

Điều đó thật tuyệt! chính xác những gì tôi muốn làm !!
Mithun Sreedharan

11
Đây là năm muộn, nhưng tôi rất ấn tượng với câu trả lời này khi nó nhảy qua tất cả các khía cạnh cú pháp và đi đúng với những gì người hỏi đang cố gắng thực hiện.
Mike Buckbee

2
+1, nhưng erb không nhất thiết ngụ ý đường ray (Sinatra, ERB độc lập, v.v.).
Fox Wilson

17

@pst đã đưa ra một câu trả lời tuyệt vời, nhưng tôi muốn đề cập rằng trong Ruby, toán tử ternary được viết trên một dòng là chính xác về mặt cú pháp, không giống như Perl và C nơi chúng ta có thể viết nó trên nhiều dòng:

(true) ? 1 : 0

Thông thường, Ruby sẽ phát sinh lỗi nếu bạn cố gắng phân chia nó thành nhiều dòng, nhưng bạn có thể sử dụng \biểu tượng tiếp tục dòng ở cuối dòng và Ruby sẽ rất vui:

(true)   \
  ? 1    \
  : 0

Đây là một ví dụ đơn giản, nhưng nó có thể rất hữu ích khi xử lý các dòng dài hơn vì nó giữ cho mã được đặt ra độc đáo.

Cũng có thể sử dụng ternary mà không có các ký tự tiếp tục dòng bằng cách đặt các toán tử cuối cùng trên dòng, nhưng tôi không thích hoặc đề nghị nó:

(true) ?
  1 :
  0

Tôi nghĩ rằng điều đó dẫn đến việc thực sự khó đọc mã khi kiểm tra có điều kiện và / hoặc kết quả lâu hơn.

Tôi đã đọc những bình luận nói rằng không nên sử dụng toán tử ternary vì nó khó hiểu, nhưng đó là một lý do tồi để không sử dụng thứ gì đó. Theo cùng một logic, chúng ta không nên sử dụng các biểu thức chính quy, toán tử phạm vi (' ..' và biến thể "flip-flop" dường như không xác định). Chúng mạnh mẽ khi được sử dụng đúng cách, vì vậy chúng ta nên học cách sử dụng chúng một cách chính xác.


Tại sao bạn đặt dấu ngoặc xung quanh true?

Hãy xem xét ví dụ của OP:

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

Kết thúc bài kiểm tra có điều kiện giúp làm cho nó dễ đọc hơn vì nó tách biệt trực quan bài kiểm tra:

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

Tất nhiên, toàn bộ ví dụ có thể được thực hiện dễ đọc hơn bằng cách sử dụng một số bổ sung hợp lý của khoảng trắng. Điều này chưa được kiểm tra nhưng bạn sẽ có ý tưởng:

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

Hoặc, được viết nhiều hơn thành ngữ:

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

Thật dễ dàng để tranh luận rằng khả năng đọc cũng bị ảnh hưởng xấu question.question.


1
Nếu đa dòng, tại sao không sử dụng nếu ... khác ... kết thúc?
Wayne Conrad

1
Vì quá nhiều năm làm việc ở Perl và C? Tôi sử dụng một trong hai, tùy thuộc vào tình huống và liệu cái này rõ ràng hơn cái kia. Đôi khi if / other quá dài dòng, đôi khi ?: Thật xấu xí.
Tin Man

1
@WayneConrad Các nếu có ít nhất một vấn đề được giải thích trong câu trả lời này: stackoverflow.com/a/4252945/2597260 Hãy so sánh một vài cách sử dụng nhiều dòng nếu / nhà điều hành ternary: gist.github.com/nedzadarek/0f9f99755d42bad10c30
Darek Nędza

Tại sao bạn đặt dấu ngoặc xung quanh true?
Zac

1
Bởi vì truethực sự đang ngồi trong những gì sẽ là một biểu thức đánh giá truehoặc false. Tốt hơn hết là phân định trực quan những cái đó vì các câu lệnh ternary có thể nhanh chóng chuyển thành nhiễu hình ảnh, làm giảm khả năng đọc ảnh hưởng đến khả năng bảo trì.
Tin Man

3

Một ví dụ đơn giản trong đó người vận hành kiểm tra xem id của người chơi có phải là 1 không và đặt id kẻ thù tùy thuộc vào kết quả

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

Và tôi tìm thấy một bài viết về chủ đề này có vẻ khá hữu ích.


4
Tại sao không enemy_id = player_id == 1 ? 2 : 1?
Aaron Blenkush

1
@AaronBlenkush Cảm ơn đầu vào thanh lịch. Tôi vẫn còn ở cấp độ noob, có lẽ đó là lý do :)
devwanderer

0

condition ? statement_A : statement_Btương đương với

if condition == true
  statement_A
else
  statement_B
end

0

Cách dễ nhất:

param_a = 1
param_b = 2

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

param_akhông bằng param_bthì resultgiá trị của nó sẽ làNot same!

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.