Que signifie | / = (Ou-equals) dans Ruby?

que signifie le code suivant dans Ruby?

||=

a-t-il un sens ou une raison pour la syntaxe?

287
demandé sur Peter O. 2009-06-15 15:25:13
la source

20 ответов

cette question a été discutée si souvent sur les listes de diffusion de Ruby et les blogs de Ruby qu'il y a maintenant même des fils sur la liste de diffusion de Ruby dont le seul but est de recueillir des liens vers tous les autres fils sur la liste de diffusion de Ruby qui discutent de cette question.

En voici un: la liste définitive de / / = (ou égale) fils et pages

Si vous vraiment veulent savoir ce qui se passe, jetez un coup d'oeil à la Section 11.4.2.3 "assignations abrégées" du Ruby Language Draft Specification .

en première approximation,

a ||= b

est équivalent à

a || a = b

et Non équivalent à

a = a || b

ce n'est Cependant qu'une première approximation, surtout si a n'est pas défini. La sémantique aussi diffèrent selon qu'il s'agit d'une assignation simple à variable, d'une assignation à méthode ou d'une assignation à indexation:

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

sont tous traités différemment.

157
répondu Jörg W Mittag 2018-04-25 10:26:06
la source

a ||= b est un" opérateur d'assignation conditionnelle". C'est sorte-de-mais-pas-tout à fait ( * ) abréviation de a || a = b .

signifie si a n'est pas défini ou falsey ( false ou nil ), alors évaluer b et mettre a au résultat ".

par exemple:

> a ||= nil
=> nil
> a ||= 0;
=> 0
> a ||= 2;
=> 0

> foo = false;
=> false
> foo ||= true;
=> true
> foo ||= false;
=> true

court-circuit de Ruby l'évaluation signifie que si a est défini et évalué à truthy, puis le côté droit de l'opérateur n'est pas évalué, et aucune cession a lieu. Cette distinction est sans importance si a et b sont toutes deux des variables locales, mais est significative si l'une ou l'autre est une méthode getter/setter d'une classe.

de façon confuse, il ressemble à d'autres opérateurs d'affectation (comme += ) mais se comporte différemment.

a += b se traduit par a = a + b

a ||= b se traduit en gros par* a || a = b

*sauf que, lorsque a n'est pas défini, a || a = b serait NameError, tandis que a ||= b définit a à b .

autres lectures:

496
répondu Steve Bennett 2018-04-10 13:05:17
la source

Concise et complète réponse

a ||= b

évalue de la même manière que chaque des lignes suivantes

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

-

d'autre part,

a = a || b

évalue de la même manière que chaque des lignes suivantes

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

-

Edit: comme AJedi32 l'a souligné dans le commentaires, ceci n'est vrai que si: 1. a est une variable définie. 2. Évaluer un programme une fois et deux fois n'entraîne pas de différence dans l'état du programme ou du système.

31
répondu the_minted 2016-03-21 02:10:05
la source

en résumé, a||=b signifie: Si a est undefined, nil or false , remplacer b par a . Sinon, gardez a intact.

22
répondu vidaica 2015-08-20 03:29:53
la source
Fondamentalement,



x ||= y signifie

si x a une valeur quelconque de le laisser tomber et de ne pas modifier la valeur, sinon mettre x à y .

12
répondu sony vizio 2017-02-18 00:39:27
la source

signifie ou-égal à. Il vérifie si la valeur de gauche est défini, puis l'utiliser. Si ce n'est pas le cas, utilisez la valeur à droite. Vous pouvez l'utiliser dans les Rails pour mettre en cache les variables d'instance dans les modèles.

un exemple basé sur les Rails rapides, où nous créons une fonction pour récupérer l'utilisateur actuellement connecté:

class User > ActiveRecord::Base

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

end

vérifie si la variable d'instance @current_user est définie. S'il l'est, il le retournera, enregistrant ainsi un appel de base de données. Si ce n'est pas définie cependant, nous faisons l'appel, puis définissez @current_user variable. C'est une technique de mise en cache très simple, mais elle est idéale lorsque vous récupérez plusieurs fois la même variable d'instance à travers l'application.

8
répondu Jamie Rumbelow 2009-06-15 15:35:58
la source
x ||= y

est

x || x = y

"si x est faux ou indéfini, puis point x de y"

8
répondu Kiattisak Anoochitarom 2013-04-11 14:56:04
la source

pour être précis, a ||= b signifie "Si a n'est pas défini ou falsy ( false ou nil ), mettre a à b et évaluer à (c.-à-d. retourner) b , autrement évaluer à a ".

D'autres tentent souvent d'illustrer cela en disant que a ||= b est équivalent à a || a = b ou a = a || b . Ces équivalences peuvent être utiles pour comprendre le concept, mais sachez qu'ils sont pas précis dans toutes les conditions. Permettez-moi d'expliquer:

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

    le comportement de ces énoncés diffère lorsque a est une variable locale non définie. Dans ce cas, a ||= b fixera a à b (et évaluera à b ), tandis que a || a = b augmentera NameError: undefined local variable or method 'a' for main:Object .

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

    l'équivalence de ces énoncés est souvent supposée, puisqu'une équivalence similaire est vraie pour d'autres opérateurs assignation abrégée (c.-à-d. += , -= , *= , /= , %= , **= , &= , |= , ^= , <<= , et >>= ). Cependant, pour ||= le comportement de ces les énoncés peuvent différer lorsque a= est une méthode sur un objet et a est véridique. Dans ce cas, a ||= b ne fera rien (autre que d'évaluer à a ), tandis que a = a || b appellera a=(a) sur a 's récepteur. Comme d'autres l'ont souligné, cela peut faire une différence lorsque l'appel a=a a des effets secondaires, tels que l'ajout de touches à un hash.

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

    le comportement de ces énoncés diffère seulement dans ce qu'ils évaluent à quand a est vrai. Dans ce cas, a = b unless a sera évalué à nil (bien que a ne sera toujours pas fixé, comme prévu), tandis que a ||= b sera évalué à a .

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

    pas Encore de. Ces énoncés peuvent différer lorsqu'il existe une méthode method_missing qui renvoie une valeur vraie pour a . Dans ce cas, a ||= b évaluera à n'importe quel retour method_missing , et ne tentera pas de définir a , tandis que defined?(a) ? (a || a = b) : (a = b) définira a à b et évaluera à b .

D'accord, d'accord, alors que est a ||= b équivalent à? Est-il un moyen de l'exprimer en Ruby?

bien, en supposant que je n'oublie rien, je crois que a ||= b est fonctionnellement équivalent à... ( roulement de tambour )

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

attendez! N'est-ce pas le premier exemple avec un noop avant? Eh bien, pas tout à fait. Rappelez-vous comment j'ai dit avant que a ||= b n'est pas équivalent à a || a = b quand a est une variable locale non définie? Bien, a = nil if false garantit que a n'est jamais indéfini, même si cette ligne n'est jamais exécutée. Les variables locales de Ruby sont définies lexicalement.

5
répondu Ajedi32 2017-05-23 15:10:44
la source

unless x x = y end

sauf si x a une valeur (elle n'est pas nulle ou fausse), mettez-la égale à y

est l'équivalent de

x ||= y

3
répondu 0r4cl3 2015-10-15 22:20:13
la source

supposez a = 2 et b = 3

alors, a ||= b sera résultée à a valeur de l 'c.-à-d. 2 .

comme lorsque a évalue à une certaine valeur non résultant à false ou nil .. C'est pourquoi il ll de ne pas évaluer la valeur de b .

supposons maintenant a = nil et b = 3 .

puis a ||= b seront résultés à 3 c'est à dire b 's de la valeur.

comme il tente d'abord d'évaluer la valeur de a qui a abouti à nil .. il a donc évalué b valeur de l'.

le meilleur exemple utilisé dans l'application ror est:

#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

Où, User.find_by_id(session[:user_id]) est déclenché si et seulement si @current_user n'est pas initialisé avant.

3
répondu Pankhuri 2016-03-17 15:00:45
la source

C'est l'affectation par défaut de la notation

par exemple: x / / = 1

ceci vérifiera si x est nul ou non. Si x est effectivement nul, il lui assignera alors cette nouvelle valeur (1 dans notre exemple)

plus explicite:

si x = = néant

x = 1

la fin de

3
répondu Max Rogers 2017-12-14 01:15:27
la source
a ||= b

est équivalent à

a || a = b

et non

a = a || b

en raison de la situation où vous définissez un hash avec une valeur par défaut (le hash retournera la valeur par défaut pour toute clé non définie)

a = Hash.new(true) #Which is: {}

si vous utilisez:

a[10] ||= 10 #same as a[10] || a[10] = 10

à une est toujours:

{}

mais quand vous écrivez:

a[10] = a[10] || 10

un devient:

{10 => true}

parce que vous avez attribué la valeur de lui-même à la clé 10 , qui est par défaut à true, donc maintenant le hachage est défini pour la clé 10 , plutôt que de ne jamais effectuer la tâche en premier lieu.

2
répondu RileyE 2013-05-13 20:26:59
la source

c'est comme une instanciation paresseuse. Si la variable est déjà définie, elle prendra cette valeur au lieu de la créer à nouveau.

2
répondu mukh007 2013-09-29 11:52:05
la source
irb(main):001:0> a = 1
=> 1
irb(main):002:0> a ||= 2
=> 1

parce que a était déjà fixé à 1

irb(main):003:0> a = nil
=> nil
irb(main):004:0> a ||= 2
=> 2

parce que a était nil

1
répondu fuzz 2015-01-16 02:42:16
la source

n'oubliez pas que ||= n'est pas une opération atomique et donc, il n'est pas sûr de fil. En règle générale, ne l'utilisez pas pour les méthodes de classe.

1
répondu Luca Guidi 2015-10-12 13:31:14
la source
b = 5
a ||= b

se traduit par:

a = a || b

qui sera

a = nil || 5

donc finalement

a = 5

maintenant si vous appelez cela à nouveau:

a ||= b
a = a || b
a = 5 || 5
a = 5

b = 6

maintenant si vous appelez cela à nouveau:

a ||= b
a = a || b
a = 5 || 6
a = 5 

si vous observez, la valeur b ne sera pas attribuée à a . a aura toujours 5 .

C'est un modèle de Mémoization qui est utilisé dans Ruby pour accélérer les accesseurs.

def users
  @users ||= User.all
end

cela se traduit essentiellement par:

@users = @users || User.all

ainsi vous ferez un appel à la base de données pour la première fois que vous appelez cette méthode.

les appels futurs à cette méthode retourneront simplement la valeur de la variable d'instance @users .

1
répondu siva krishna reddy 2016-10-21 03:07:15
la source

comme une idée fausse commune a||=b n'est pas équivalent à a = a||b, mais il est, mais il se comporte comme un || a = b

Mais voici un cas délicat

si a n'est pas défini, a || A = 42 soulève NameError, tandis que a ||= 42 renvoie 42. Donc, ils ne semblent pas être des expressions équivalentes.

0
répondu tessie 2016-08-25 09:14:12
la source

||= s'appelle un opérateur d'assignation conditionnelle.

il fonctionne essentiellement comme = mais à l'exception que si une variable a déjà été assignée il ne fera rien.

premier exemple:

x ||= 10

Second exemple:

x = 20
x ||= 10

Dans le premier exemple x est maintenant égal à 10. Cependant, dans le deuxième exemple x est déjà défini comme 20. Si l'opérateur conditionnel n'a aucun effet. x est toujours 20 après x ||= 10 .

0
répondu Charlie Wood 2017-04-03 16:48:00
la source

a ||= b est la même chose que a = b if a.nil? ou a = b unless a

mais les 3 options présentent-elles la même performance? Avec Ruby 2.5.1 ce

1000000.times do
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
end

prend 0.099 secondes sur mon PC, tandis que

1000000.times do
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
end

prend 0.062 secondes. C'est près de 40% plus rapide.

et puis nous avons aussi:

1000000.times do
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
end

qui prend 0,166 secondes.

non pas que cela aura un impact significatif sur les performances en général, mais si vous avez besoin de ce dernier bit d'optimisation, alors considérez ce résultat. D'ailleurs: a = 1 unless a est plus facile à lire pour le novice, il est explicite.

Note 1: le fait de répéter plusieurs fois la ligne d'assignation a pour but de réduire la hauteur de la boucle à l'heure mesurée.

Note 2: les résultats sont similaires si je fais a=nil néant avant chaque affectation.

0
répondu Ymox 2018-08-28 18:50:46
la source

||= est un conditionnel opérateur d'affectation

  x ||= y

est équivalent à

  x = x || y

ou alternativement

if defined?(x) and x
    x = x
else 
    x = y
end
0
répondu Sunda 2018-09-01 07:51:23
la source

Autres questions sur ruby operators