Понимание "||" Оператор ИЛИ в условных выражениях в Ruby - PullRequest
34 голосов
/ 12 октября 2009

Вкратце, почему следующие три строки не идентичны по своему воздействию?

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

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

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

Первый дает мне желаемый результат, но поскольку на самом деле вариантов больше, чем просто проекты и детали, использование этой формы создает подробное утверждение. Два других более компактны, но не дают мне тот же результат.

Ответы [ 9 ]

56 голосов
/ 12 октября 2009

точная семантика || являются:

  • если первое выражение не ноль или ложь, вернуть его
  • если первое выражение равно nil или false, вернуть второе выражение

Итак, как работает ваше первое выражение, если @controller.controller_name == "projects", то выражение замыкается и возвращает true. если нет, он проверяет второе выражение. второй и третий варианты по существу if @controller.controller_name == "projects", поскольку "projects" || "parts" равно "projects". Вы можете попробовать это в irb:

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

что вы хотите сделать, это

if ["projects", "parts"].include? @controller.controller_name
7 голосов
/ 12 октября 2009

Разница в порядке происходящего. Также || не делает то, что вы думаете, что делает в 2 и 3.

Вы также можете сделать

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

чтобы уменьшить код в будущем, если вам нужно добавить больше совпадений.

6 голосов
/ 12 октября 2009

|| также является нулевым оператором объединения, поэтому

"projects" || "parts"

вернет первую строку, которая не равна нулю (в данном случае «projects»), что означает, что во вторых двух примерах вы всегда будете оценивать:

if @controller.controller_name == "projects"

Запустив irb, вы можете убедиться, что это происходит:

a = "projects"
b = "parts"

a || b

возвращает projects

4 голосов
/ 12 октября 2009

Там происходит несколько разных вещей:

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

это дает то поведение, которое вы хотите, я предполагаю. Логика довольно проста: вернуть true, если имя контроллера - "projects" или "parts"

Другой способ сделать это:

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

Это проверит, находится ли имя контроллера где-то в списке.

Теперь для других примеров:

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

Это не будет делать то, что вы хотите. Сначала он оценит ("projects" || "parts") (что приведет к "проектам"), а затем будет только проверять, совпадает ли имя контроллера с этим.

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

Этот становится еще более странным. Это всегда приведет к истине. Сначала он проверит, совпадает ли имя контроллера с «проектами». Если это так, утверждение оценивается как истинное. Если нет, то он оценивает «части» сам по себе: который также оценивается как «истина» в ruby ​​(любой объект, отличный от нуля, считается «истинным» для целей булевой логики »)

3 голосов
/ 12 октября 2009

По сути, == не распространяется на других операторов. Причина 3 * (2+1) совпадает с 3 * 2 + 3 * 1 в том, что умножение распределяется по сложению.

Значение || выражение будет одним из его аргументов. Таким образом, 2-е утверждение эквивалентно:

if @controller.controller_name == "projects"

|| имеет более низкий приоритет , чем ==, поэтому третье утверждение эквивалентно:

if (@controller.controller_name == "projects") || "ports"
2 голосов
/ 12 октября 2009

Простой способ получить не многословное решение -

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

Это на самом деле не имеет ничего общего с ||, а скорее с тем, что значения считаются истинными в ruby. Все, кроме ложь и ноль это правда.

1 голос
/ 12 октября 2009

Логическое или оператор || работает с логическими выражениями, поэтому с помощью это на строках не делает то, что вы хотите.

Есть несколько способов добиться того, что вы хотите, которые менее подробны и более читабельны.

Использование Array # include? и простое выражение if:

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

Использование оператора case:

case @controller.controller_name
when "projects", "parts" then
  do_something
else
  do_something_else
end
0 голосов
/ 28 июня 2019

Я вижу, что многие люди предпочитают сравнение include?.

Я предпочитаю использовать оператор .in?. Это намного более кратко. А также более читабельно, поскольку мы не задаем вопросы к массиву , мы задаем вопросы к переменной, которую вы хотите задать: В вашем случае, имя контроллера .

@controller.controller_name.in? ["projects", "parts"]

Или еще лучше

@controller.controller_name.in? %w[projects parts]
0 голосов
/ 12 октября 2009

Первый сравнивает строковые литералы "projects" и "parts" с переменной @controller.controller_name.

Второй оценивает ("projects" || "parts"), что является "projects", потому что строковый литерал "projects" не имеет ни false или nil, ни пустой строки, и сравнивает ее с @controller.controller_name

Третий сравнивает @controller.controller_name и "проекты" и, если они равны, возвращает true, если они не равны, возвращает "части", что равно true для if оператора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...