Câu lệnh tình huống có nhiều giá trị trong mỗi khối 'khi'


314

Cách tốt nhất tôi có thể mô tả những gì tôi đang tìm kiếm là cho bạn thấy mã thất bại mà tôi đã thử cho đến nay:

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

Tôi đã có khoảng 4 hoặc 5 whentình huống khác nhau sẽ được kích hoạt bởi khoảng 50 giá trị khác nhau có thể có car. Có cách nào để làm điều này với casecác khối hay tôi nên thử một khối lớn if?

Câu trả lời:


669

Trong một casetuyên bố, a ,là tương đương với ||trong một iftuyên bố.

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

Một số điều khác bạn có thể làm với một tuyên bố trường hợp Ruby


1
Liên kết này có một bản tóm tắt tốt hơn về các báo cáo trường hợp trong Ruby (và nó cũng bao gồm các ví dụ về cú pháp regrec và splat).
rsenna

Tôi không biết tại sao, nhưng tình huống kỳ lạ này xảy ra: Khi tôi viết bài này : when "toyota", "lexus", tôi nhận được : unexpected tSTRING_BEG, expecting keyword_do or '{' or '(' (SyntaxError). Tuy nhiên, khi tôi viết điều này : when "toyota","lexus", nó hoạt động. Sự khác biệt duy nhất là một khoảng trắng sau dấu phẩy.
Furkan Ayhan

@FurkanAyhan Thật kỳ lạ. Tôi đã đi trước và kiểm tra mã chỉ để đảm bảo và nó hoạt động. Tôi đoán là có một cái gì đó khác đang diễn ra trong mã của bạn khiến nó bị lỗi như thế. Có thể bạn đã quên đóng một chuỗi ở đâu đó hoặc một cái gì đó như thế?
Charles Caldwell

1
tốt, điều này hoạt động, nhưng khi ruby ​​tập trung vào sự dễ dàng của lập trình viên, tôi tự hỏi tại sao nó không hỗ trợ tiêu chuẩn | | hay 'hoặc'? Điều này thật khó hiểu
Zia Ul Rehman Mughal

2
Ruby không hỗ trợ orhoặc ||ở đây vì whencó một loạt các biểu thức được phân tách bằng dấu phẩy ở bên phải của nó, không phải là một định danh duy nhất. Bởi vì điều này, nếu bạn có when a or b, không rõ liệu điều này có được coi là tương đương với when a, bhay không when (a or b), cái sau sẽ đánh giá biểu thức a or btrước khi ném nó vào lúc nào. Thật đáng ngạc nhiên và ít dễ xử lý hơn khi ngôn ngữ có các mã thông báo thay đổi hành vi dựa trên ngữ cảnh và sau đó bạn sẽ không thể sử dụng orbiểu thức thực ở bên phải khi nào.
Taywee

99

Bạn có thể tận dụng cú pháp "splat" hoặc làm phẳng của ruby.

Điều này làm cho whencác mệnh đề phát triển quá mức - bạn có khoảng 10 giá trị để kiểm tra trên mỗi nhánh nếu tôi hiểu chính xác - theo quan điểm của tôi dễ đọc hơn một chút. Ngoài ra, bạn có thể sửa đổi các giá trị để kiểm tra trong thời gian chạy. Ví dụ:

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

Một cách tiếp cận phổ biến khác là sử dụng hàm băm làm bảng điều phối, với các khóa cho mỗi giá trị carvà các giá trị là một số đối tượng có thể gọi được gói gọn mã bạn muốn thực thi.


Đây là những gì tôi đã sử dụng, mặc dù tôi cảm thấy rất tệ khi lấy đi dấu kiểm của ai đó: D
Nick

Giải pháp rực rỡ cho hàng dài when. Cám ơn vì đã chia sẻ.
Pistos

0

Một cách hay khác để đưa logic của bạn vào dữ liệu là như thế này:

# 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

Tôi không có ý thô lỗ, nhưng tôi đã từ chối vì điều này kém hiệu quả hơn cả về thời gian và không gian. Nó cũng phức tạp hơn và ít đọc hơn hai câu trả lời còn lại. Điều gì sẽ là lợi ích của việc sử dụng phương pháp này?
Nick

Nó đặt toàn bộ phân loại của bạn vào một đối tượng. Bây giờ bạn có thể thực hiện mọi thứ với đối tượng đó, chẳng hạn như tuần tự hóa nó và gửi cho người khác để giải thích logic của bạn hoặc lưu trữ nó trong cơ sở dữ liệu và cho phép mọi người chỉnh sửa nó. (Logic sẽ thay đổi khá sớm khi các mẫu xe mới xuất hiện, phải không?) Bạn có thể tra cứu "điều khiển bằng bàn".
Hew Wolff

YAGNI ("Bạn sẽ không cần nó") có thể áp dụng ở đây. Thiết kế hy sinh hiệu quả thời gian / không gian và khả năng đọc cho một kịch bản có thể tồn tại trong tương lai nhưng chưa tồn tại. Chi phí được trả ngay bây giờ, nhưng phần thưởng có thể không bao giờ được gặt hái.
Nick
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.