Что означает || = (или-равно) в Ruby? - PullRequest
310 голосов
/ 15 июня 2009

Что означает следующий код в Ruby?

||=

Имеет ли оно какое-либо значение или причину для синтаксиса?

Ответы [ 22 ]

535 голосов
/ 05 февраля 2013

a ||= b является оператором условного присвоения . Это означает , если a не определено или falsey , тогда оцените b и установите a в результат . Эквивалентно, если a определен и оценивается как истинный, то b не оценивается, и присвоение не происходит. Например:

a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0

foo = false # => false
foo ||= true # => true
foo ||= false # => true

сбивает с толку, он похож на другие операторы присваивания (например, +=), но ведет себя по-другому.

  • a += b переводится как a = a + b
  • a ||= b примерно переводится как a || a = b

Это почти сокращение от a || a = b. Разница в том, что когда a не определено, a || a = b повысит NameError, тогда как a ||= b устанавливает a в b. Это различие неважно, если a и b являются локальными переменными, но имеет значение, если любой из них является методом получения / установки класса.

Дальнейшее чтение:

169 голосов
/ 24 марта 2010

Этот вопрос так часто обсуждался в списках рассылки Ruby и блогах Ruby, что в списке рассылки Ruby теперь даже есть темы, единственная цель которых - собирать ссылки на все остальные темы в список рассылки Ruby, где обсуждается эта проблема.

Вот один из них: Окончательный список || = (ИЛИ равно) тем и страниц

Если вы действительно хотите знать, что происходит, взгляните на Раздел 11.4.2.3 «Сокращенные назначения» черновой спецификации языка Ruby .

В первом приближении

a ||= b

эквивалентно

a || a = b

и не эквивалентно

a = a || b

Однако это только первое приближение, особенно если a не определено. Семантика также различается в зависимости от того, является ли это простым назначением переменной, назначением метода или назначением индексации:

a    ||= b
a.c  ||= b
a[c] ||= b

все рассматриваются по-разному.

32 голосов
/ 23 августа 2013

Краткий и полный ответ

a ||= b

оценивается так же, как каждая из следующих строк

a || a = b
a ? a : a = b
if a then a else a = b end

-

С другой стороны,

a = a || b

оценивается так же, как каждая следующих строк

a = a ? a : b
if a then a = a else a = b end

-

Редактировать: Как указал AJedi32 в комментариях, это верно только в том случае, если: 1. a является определенной переменной. 2. Оценка один раз и два раза не приводит к разнице в состоянии программы или системы.

23 голосов
/ 11 января 2014

Короче говоря, a||=b означает: если a равно undefined, nil or false, присвойте b a. В противном случае оставьте a нетронутым.

12 голосов
/ 05 июня 2016
В принципе,


x ||= y означает

если x имеет какое-либо значение, оставьте его в покое и не изменяйте значение, в противном случае установите x в y

10 голосов
/ 15 июня 2009

Это означает или равно. Он проверяет, определено ли значение слева, а затем используйте его. Если это не так, используйте значение справа. Вы можете использовать его в Rails для кэширования переменных экземпляра в моделях.

Быстрый пример на основе Rails, где мы создаем функцию для извлечения текущего пользователя, вошедшего в систему:

class User > ActiveRecord::Base

  def current_user
    @current_user ||= User.find_by_id(session[:user_id])
  end

end

Он проверяет, установлена ​​ли переменная экземпляра @current_user. Если это так, он вернет его, тем самым сохраняя вызов базы данных. Однако, если он не установлен, мы делаем вызов, а затем устанавливаем переменную @current_user. Это действительно простая техника кэширования, но она отлично подходит для случаев, когда вы извлекаете одну и ту же переменную экземпляра из приложения несколько раз.

8 голосов
/ 11 апреля 2013
x ||= y

есть

x || x = y

"если x ложно или не определено, то x указывает на y"

7 голосов
/ 24 декабря 2014

Если быть точным, a ||= b означает "если a не определено или является ложным (false или nil), установите a в b и оцените (т.е. верните) b, в противном случае оцените a ".

Другие часто пытаются проиллюстрировать это, говоря, что a ||= b эквивалентно a || a = b или a = a || b. Эти эквивалентности могут быть полезны для понимания концепции, но имейте в виду, что они не точны при любых условиях. Позвольте мне объяснить:

  • a ||= ba || a = b?

    Поведение этих операторов отличается, когда a является неопределенной локальной переменной. В этом случае a ||= b установит a на b (и оценит b), тогда как a || a = b повысит NameError: undefined local variable or method 'a' for main:Object.

  • a ||= ba = a || b?

    Эквивалентность этих утверждений часто предполагается, поскольку аналогичная эквивалентность верна для других сокращенных операторов присваивания (т.е. +=, -=, *=, /=, %= **=, &=, |=, ^=, <<= и >>=). Однако для ||= поведение этих операторов может отличаться, когда a= является методом объекта, а a является правдивым. В этом случае a ||= b ничего не будет делать (кроме оценки a), тогда как a = a || b вызовет a=(a) на приемнике a. Как указали другие , это может иметь значение, если вызов a=a имеет побочные эффекты, такие как добавление ключей в хеш.

  • a ||= ba = b unless a ??

    Поведение этих утверждений отличается только тем, к чему они относятся, когда a является правдивым. В этом случае a = b unless a будет иметь значение nil (хотя a все равно не будет установлено, как ожидалось), тогда как a ||= b будет иметь значение a.

  • a ||= bdefined?(a) ? (a || a = b) : (a = b) ????

    Все еще нет. Эти утверждения могут отличаться, если существует метод method_missing, который возвращает истинное значение для a. В этом случае a ||= b будет вычислять все, что вернет method_missing, и не будет пытаться установить a, тогда как defined?(a) ? (a || a = b) : (a = b) установит a в b и оценит в b.

Хорошо, хорошо, так что эквивалентно a ||= b? Есть ли способ выразить это в Ruby?

Ну, если предположить, что я ничего не пропускаю, я считаю, что a ||= b функционально эквивалентен ... ( drumroll )

begin
  a = nil if false
  a || a = b
end

Держись! Разве это не первый пример с noop перед ним? Ну, не совсем. Помните, как я говорил ранее, a ||= b не эквивалентен a || a = b, когда a является неопределенной локальной переменной? Ну, a = nil if false гарантирует, что a никогда не будет неопределенным, даже если эта строка никогда не выполняется. Локальные переменные в Ruby имеют лексическую область видимости.

3 голосов
/ 15 октября 2015

unless x x = y end

если x не имеет значения (это не ноль или ложь), установите его равным y

эквивалентно

x ||= y

3 голосов
/ 10 августа 2013

Предположим a = 2 и b = 3

THEN, a ||= b будет приведено к значению a, т.е. 2.

То же самое, когда a оценивается как некоторое значение, не приведенное к false или nil .. Поэтому ll не оценивает значение b.

Теперь предположим, a = nil и b = 3.

Тогда a ||= b будет приведено к 3, т.е. b.

Когда он сначала попытается оценить значение a, которое привело к nil .., он оценил значение b.

Лучший пример, используемый в приложении ror:

#To get currently logged in iser
def current_user
  @current_user ||= User.find_by_id(session[:user_id])
end

# Make current_user available in templates as a helper
helper_method :current_user

Где User.find_by_id(session[:user_id]) запускается тогда и только тогда, когда @current_user не инициализировался ранее.

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