2009-10-12 42 views
20

Chỉ một thời gian ngắn, tại sao ba dòng sau không giống nhau về tác động của chúng?Hiểu "||" Toán tử OR trong Nếu điều kiện trong Ruby

if @controller.controller_name == "projects" || @controller.controller_name == "parts" 

if @controller.controller_name == ("projects" || "parts") 

if @controller.controller_name == "projects" || "parts" 

Đầu tiên cung cấp cho tôi kết quả tôi muốn, nhưng thực tế có nhiều tùy chọn hơn là chỉ các dự án và các phần, sử dụng biểu mẫu đó tạo ra tuyên bố chi tiết. Hai cái còn lại nhỏ gọn hơn nhưng không cho tôi kết quả tương tự.

Trả lời

38

ngữ nghĩa chính xác của || là:

  • nếu biểu hiện đầu tiên là không bằng không hoặc sai sự thật, trả lại
  • nếu biểu hiện đầu tiên là con số không hoặc sai sự thật, trả lại biểu thức thứ hai

vì vậy những gì biểu hiện đầu tiên của bạn hoạt động ra là, nếu @controller.controller_name == "projects", thì biểu thức ngắn mạch và trả về true. nếu không, nó sẽ kiểm tra biểu thức thứ hai. biến thể thứ hai và thứ ba về cơ bản là if @controller.controller_name == "projects", kể từ "projects" || "parts" bằng "projects". bạn có thể thử điều này trong IRB:

>> "projects" || "parts" 
=> "projects" 

những gì bạn muốn làm là

if ["projects", "parts"].include? @controller.controller_name 
5

|| cũng là một nhà điều hành coalescing null, nên

"projects" || "parts" 

sẽ trả về chuỗi đầu tiên mà không phải là null (trong trường hợp này "dự án"), có nghĩa là trong hai ví dụ thứ hai, bạn sẽ luôn luôn được đánh giá:

if @controller.controller_name == "projects" 

đánh lửa IRB, bạn có thể kiểm tra điều này xảy ra:

a = "projects" 
b = "parts" 

a || b 

trả lại projects

+4

thực sự,' hoặc'ing hai chuỗi cùng nhau sẽ cung cấp cho bạn chuỗi đầu tiên, để hỗ trợ các thành ngữ như 'a || =" hello "' và 'a = somefunc() || default' –

+0

Bạn hoàn toàn chính xác. Tôi đã cập nhật câu trả lời của mình. – jerhinesmith

6

Sự khác biệt là thứ tự của những gì đang xảy ra. Ngoài ra || không được làm những gì bạn nghĩ nó trong vòng 2 và 3.

Bạn cũng có thể làm

if ['projects','parts'].include?(@controller.controller_name) 

để giảm mã trong tương lai nếu bạn cần thêm các trận đấu nhiều hơn nữa.

2

Cách đơn giản để có được một giải pháp không verbose là

if ["a", "b", "c"].include? x 

Điều này thực sự không có gì để làm với ||, mà là những gì giá trị được coi là đúng trong ruby. Tất cả mọi thứ tiết kiệm sai và nil là sự thật.

0

Đầu tiên so sánh chữ "dự án" và "phần" chuỗi ký tự với biến số @controller.controller_name.

Second một đánh giá lại ("dự án" || "bộ phận") đó là "dự án" bởi vì "dự án" chuỗi chữ không false hoặc nil hoặc chuỗi rỗng và so sánh nó với @controller.controller_name

Thứ ba ta so sánh @controller.controller_name và " các dự án "và nếu chúng bằng nhau, nó trả về true, nếu chúng không trả lại" các phần "bằng true cho tuyên bố if.

1

Lý do hoặc toán tử || hoạt động trên các biểu thức boolean, do đó, sử dụng trên chuỗi không làm những gì bạn muốn.

Có một số cách để đạt được những gì bạn muốn ít chi tiết hơn và dễ đọc hơn.

Sử dụng mảng # include? và một lệnh if-đơn giản:

if ["projects", "parts"].include? @controller.controller_name 
    do_something 
else 
    do_something_else 
end 

Sử dụng một trường tuyên bố:

case @controller.controller_name 
when "projects", "parts" then 
    do_something 
else 
    do_something_else 
end 
3

Về cơ bản, == không phân phối qua các nhà khai thác khác. Lý do 3 * (2+1) giống với 3 * 2 + 3 * 1 là phép nhân phân phối trên bổ sung.

Giá trị của || biểu thức sẽ là một trong các đối số của nó. Do đó, tuyên bố thứ 2 tương đương với:

if @controller.controller_name == "projects" 

|| là thấp hơn precedence ==, vì vậy báo cáo kết quả thứ 3 là tương đương với:

if (@controller.controller_name == "projects") || "ports" 
2

Có một vài điều khác nhau xảy ra ở đó:

if @controller.controller_name == "projects" || @controller.controller_name == "parts" 

này mang lại cho hành vi mà bạn muốn tôi giả. Logic là khá cơ bản: return true nếu tên khiển là một trong hai "dự án" hoặc "phụ tùng"

Một cách khác để làm điều này là:

if ["projects", "parts", "something else..."].include? @controller.controller_name 

Đó sẽ kiểm tra nếu tên điều khiển là đâu đó trong danh sách.

Bây giờ cho các ví dụ khác:

if @controller.controller_name == ("projects" || "parts") 

này sẽ không làm những gì bạn muốn. Nó sẽ đánh giá ("projects" || "parts") đầu tiên (mà sẽ dẫn đến "dự án"), và sau đó sẽ chỉ kiểm tra nếu tên bộ điều khiển bằng với điều đó.

if @controller.controller_name == "projects" || "parts" 

Điều này thậm chí còn trở nên tồi tệ hơn. Điều này sẽ luôn luôn dẫn đến sự thật. Đầu tiên nó sẽ kiểm tra xem tên bộ điều khiển có bằng "dự án" hay không. Nếu vậy, câu lệnh đánh giá là đúng. Nếu không, nó đánh giá "các bộ phận" trên chính nó: nó cũng đánh giá là "true" trong ruby ​​(bất kỳ đối tượng không nil nào được coi là "true" cho mục đích của logic boolean ")

Các vấn đề liên quan