Что означает следующий код в Ruby?
||=
Имеет ли это какое-либо значение или причину для синтаксиса?
Этот вопрос обсуждался так часто в списках рассылки 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
все относятся по-разному.
a = false; a ||= true
вовсе не делать то , что ваш ответ говорит , что это делает «нюанс».a ||= b
является условным оператором присваивания . Это означает, что если значениеa
undefined или false , то оценитеb
и установитеa
результат . Эквивалентно, еслиa
определено и оценивается как правдивое, тоb
не оценивается, и присвоение не происходит. Например:Это сбивает с толку, оно похоже на другие операторы присваивания (например,
+=
), но ведет себя по-другому.a += b
переводит наa = a + b
a ||= b
примерно переводится какa || a = b
Это почти сокращение для
a || a = b
. Разница в том, что, когда значениеa
не определено,a || a = b
будет повышатьсяNameError
, тогда какa ||= b
устанавливаетсяa
наb
. Это различие неважно, еслиa
иb
являются локальными переменными, и имеет значение, если любой из них является методом получения / установки класса.Дальнейшее чтение:
источник
h = Hash.new(0); h[1] ||= 2
. Теперь рассмотрим два возможных расширенияh[1] = h[1] || 2
противh[1] || h[1] = 2
. Оба выражения имеют значение,0
но первое излишне увеличивает размер хэша. Возможно, именно поэтому Матц решил сделать||=
поведение более похожим на второе расширение. (Я основал это на примере одной из тем, связанных с другим ответом.)a || a = b
поднимает,NameError
еслиa
неопределено.a ||= b
нет, но вместо этого инициализируетa
и устанавливает егоb
. Это единственное различие между этими двумя, насколько я знаю. Точно так же единственное различие междуa = a || b
и тем,a ||= b
что я знаю, заключается в том, что еслиa=
это метод, он будет вызываться независимо от того, чтоa
возвращает. Кроме того , единственное различие междуa = b unless a
иa ||= b
что я знаю, что это заявление имеет значение ,nil
а неa
еслиa
это truthy. Множество приближений, но ничего совершенно не эквивалентного ...Краткий и полный ответ
оценивается так же, как каждая из следующих строк
-
С другой стороны,
оценивается так же, как каждая из следующих строк
-
Редактировать: Как AJedi32 указал в комментариях, это верно только в том случае, если: 1. a является определенной переменной. 2. Оценка один раз и два раза не приводит к разнице в состоянии программы или системы.
источник
a
false / zero / undefined, он оценивается дважды. (Но я не знаю Руби, поэтому я не знаю, можно ли точно оценить lvalues ...)a || a = b
,a ? a : a = b
,if a then a else a = b end
, Иif a then a = a else a = b end
выдаст ошибку , еслиa
не определено, тогдаa ||= b
иa = a || b
не будет. Кроме того ,a || a = b
,a ? a : a = b
,if a then a else a = b end
,a = a ? a : b
, иif a then a = a else a = b end
оценить вa
два раза , когдаa
это truthy, в то время какa ||= b
иa = a || b
нет.a || a = b
не будет оцениватьсяa
дважды, когдаa
это правда.the end state will be equivalent after the whole line has been evaluated
Это не обязательно правда, хотя. Что еслиa
это метод? Методы могут иметь побочные эффекты. Например, Сpublic; def a=n; @a=n; end; def a; @a+=1; end; self.a = 5
,self.a ||= b
вернется 6, ноself.a ? self.a : self.a = b
вернется 7.Короче говоря,
a||=b
означает: Еслиa
естьundefined, nil or false
, правопреемникb
вa
. В противном случае, оставайтесьa
нетронутыми.источник
x ||= y
средстваесли
x
имеет какое-либо значение, оставьте его в покое и не изменяйте значение, в противном случае установитеx
значениеy
источник
Это означает или равно. Он проверяет, определено ли значение слева, а затем используйте его. Если это не так, используйте значение справа. Вы можете использовать его в Rails для кэширования переменных экземпляра в моделях.
Быстрый пример на основе Rails, где мы создаем функцию для извлечения текущего пользователя:
Он проверяет, установлена ли переменная экземпляра @current_user. Если это так, он вернет его, тем самым сохраняя вызов базы данных. Однако, если он не установлен, мы делаем вызов, а затем устанавливаем переменную @current_user. Это действительно простая техника кэширования, но она отлично подходит для случаев, когда вы выбираете одну и ту же переменную экземпляра в приложении несколько раз.
источник
undefined
, но и включаетсяfalse
иnil
, что может не иметь отношения к делуcurrent_user
, но особенноfalse
может быть непредсказуемым в других случаяхявляется
«если x ложно или не определено, то x указывает на y»
источник
Чтобы быть точным,
a ||= b
означает «еслиa
не определено или falsy (false
илиnil
), установитеa
дляb
и вычисляться (т.е. возвращение)b
, в противном случае вычислятьсяa
».Другие часто пытаются проиллюстрировать это, говоря, что
a ||= b
это эквивалентноa || a = b
илиa = a || b
. Эти эквивалентности могут быть полезны для понимания концепции, но имейте в виду, что они не точны при любых условиях. Позвольте мне объяснить:a ||= b
⇔a || a = b
?Поведение этих операторов отличается, когда
a
является неопределенной локальной переменной. В этом случае,a ||= b
будет установленa
вb
(и оценивать сb
), в то время какa || a = b
поднимутNameError: undefined local variable or method 'a' for main:Object
.a ||= b
⇔a = a || b
?Эквивалентность этих утверждений часто предполагается, так как аналогичные эквивалентности верно и для других сокращенно назначений операторов (т.е.
+=
,-=
,*=
,/=
,%=
,**=
,&=
,|=
,^=
,<<=
, и>>=
). Однако||=
поведение этих операторов может отличаться, когдаa=
метод является объектом иa
является правдивым. В этом случаеa ||= b
не будет делать ничего (кроме вычислятьсяa
), в то время какa = a || b
позвонитa=(a)
наa
приемник «s. Как уже отмечали другие , это может иметь значение, когда у вызоваa=a
есть побочные эффекты, такие как добавление ключей в хеш.a ||= b
⇔a = b unless a
??Поведение этих утверждений отличается только тем, что они оценивают, когда
a
правдиво. В этом случаеa = b unless a
будет оцениватьсяnil
(хотяa
все равно не будет установлено, как ожидается), тогда какa ||= b
будет оцениватьсяa
.a ||= b
⇔defined?(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
это функционально эквивалентно ... ( барабанная дробь )Оставайтесь на линии! Разве это не первый пример с noop перед ним? Ну, не совсем. Помните, как я говорил ранее,
a ||= b
это не эквивалентно тому,a || a = b
когдаa
неопределенная локальная переменная? Хорошо,a = nil if false
гарантирует, чтоa
это никогда не будет неопределенным, даже если эта строка никогда не выполняется. Локальные переменные в Ruby имеют лексическую область видимости.источник
(a=b unless a) or a
a
это метод, он будет вызываться дважды, а не один раз (если он возвращает истинное значение в первый раз). Это может привести к отличиям в поведении, если, например,a
возвращение занимает много времени или имеет побочные эффекты.b
кa
, не в шк еще назначить на LHS, или другими словами, не в л.ш. до сих пор установить его значение в правой части?a ||= b
ответ, который я нашел в Интернете. Спасибо.unless x x = y end
если х не имеет значения (это не ноль или ложь), установите его равным у
эквивалентно
x ||= y
источник
Предположим
a = 2
иb = 3
ТОГДА,
a ||= b
будет приведено кa
«S значение , т.е.2
.Как, например, когда a оценивает какое-то значение, не приведенное к
false
илиnil
.. Поэтому оноll
не оцениваетb
значение.Теперь предположим
a = nil
иb = 3
.Тогда
a ||= b
будет приведено значение3
ieb
.Когда он сначала попытается оценить значение a, которое привело к
nil
..., он также оценилb
значение.Лучший пример, используемый в приложении ror:
Где,
User.find_by_id(session[:user_id])
запускается тогда и только тогда, когда@current_user
не инициализирован ранее.источник
a || = b
Указывает, присутствует ли какое-либо значение в «a», и вы не хотите изменять его, продолжая использовать это значение, иначе, если «a» не имеет никакого значения, используйте значение «b».
Простые слова, если слева, если не ноль, указывают на существующее значение, в противном случае указывают на значение справа.
источник
эквивалентно
и нет
из-за ситуации, когда вы определяете хеш со значением по умолчанию (хеш вернет значение по умолчанию для любых неопределенных ключей)
если вы используете:
А еще:
но когда вы пишете это так:
становится:
потому что вы присвоили значение себе в ключе
10
, которое по умолчанию равно true, поэтому теперь для ключа определен хэш10
, а не выполнять его в первую очередь.источник
Это как ленивый экземпляр. Если переменная уже определена, она примет это значение вместо того, чтобы создавать значение снова.
источник
Пожалуйста, помните, что
||=
это не атомарная операция и поэтому она не является поточно-ориентированной. Как правило, не используйте его для методов класса.источник
Это обозначение назначения по умолчанию
например: x || = 1
это проверит, чтобы видеть, является ли x нулем или нет. Если x действительно равен nil, ему будет присвоено это новое значение (1 в нашем примере)
более явно:
если x == nil
x = 1
end
источник
nil
илиfalse
не толькоnil
|| = - оператор условного присваивания
эквивалентно
или в качестве альтернативы
источник
Если значение
X
НЕ имеет, ему будет присвоено значениеY
. Иначе, это сохранит свое первоначальное значение, 5 в этом примере:источник
Как распространенное заблуждение,
a ||= b
не эквивалентноa = a || b
, но ведет себя какa || a = b
.Но тут возникает сложный случай. Если
a
не определено,a || a = 42
повышаетсяNameError
, покаa ||= 42
возвращается42
. Таким образом, они не кажутся эквивалентными выражениями.источник
||=
присваивает значение вправо, только если left == nil (или не определено или false).источник
Это синтаксис рубинового языка. Правильный ответ - проверить документацию ruby-lang. Все остальные объяснения запутывают .
Google
"ruby-lang docs Сокращенное Назначение".
Руби-Ланг документы
https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment
источник
Потому что
a
уже был установлен1
Потому что
a
былnil
источник
Это переводится как:
которые будут
так наконец
Теперь, если вы позвоните это снова:
Теперь, если вы позвоните это снова:
Если вы наблюдаете,
b
значение не будет присвоеноa
.a
все еще будет5
.Это шаблон памятки, который используется в Ruby для ускорения доступа.
Это в основном означает:
Таким образом, вы вызовете базу данных в первый раз, когда вызовете этот метод.
Будущие вызовы этого метода просто вернут значение
@users
переменной экземпляра.источник
||=
называется оператором условного присваивания.Это в основном работает как,
=
но за исключением того, что, если переменная уже была назначена, она ничего не будет делать.Первый пример:
Второй пример:
В первом примере
x
теперь равно 10. Однако во втором примереx
уже определено как 20. Таким образом, условный оператор не имеет эффекта.x
еще 20 после бегаx ||= 10
.источник
a ||= b
это то же самое, что сказатьa = b if a.nil?
илиa = b unless a
Но все ли 3 варианта показывают одинаковую производительность? С Ruby 2.5.1 это
занимает на моем ПК 0.099 секунды, в то время как
занимает 0,062 секунды. Это почти на 40% быстрее.
и тогда мы также имеем:
что занимает 0,166 секунды.
Не то чтобы это оказало значительное влияние на производительность в целом, но если вам нужен последний бит оптимизации, рассмотрите этот результат. Кстати:
a = 1 unless a
новичку легче читать, это само за себя.Примечание 1: причина повторения строки назначения несколько раз состоит в том, чтобы уменьшить накладные расходы цикла на измеренное время.
Примечание 2: результаты аналогичны, если я делаю
a=nil
ноль перед каждым заданием.источник