operadores - porcentaje en ruby




¿Qué significa ||=(o igual) en Ruby? (14)

¿Qué significa el siguiente código en Ruby?

||=

¿Tiene algún significado o razón para la sintaxis?


Respuesta concisa y completa

a ||= b

Se evalúa de la misma manera que cada una de las siguientes líneas.

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

-

Por otra parte,

a = a || b

Se evalúa de la misma manera que cada una de las siguientes líneas.

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

-

Edición: como lo señaló AJedi32 en los comentarios, esto solo es válido si: 1. a es una variable definida. 2. La evaluación de una vez y dos veces no produce una diferencia en el estado del programa o del sistema.


En resumen, a||=b significa: si a undefined, nil or false está undefined, nil or false , asigne b a a . De lo contrario, mantenga intacto.


Esta es la notación de asignación predeterminada

por ejemplo: x || = 1
Esto verificará si x es nula o no. Si x es de hecho nulo, entonces le asignará ese nuevo valor (1 en nuestro ejemplo)

más explícito:
si x == nil
x = 1
fin


Esta pregunta se ha discutido con tanta frecuencia en las listas de correo de Ruby y en los blogs de Ruby que ahora hay incluso hilos en la lista de correo de Ruby cuyo único propósito es recopilar enlaces a todos los demás hilos de la lista de correo de Ruby que tratan este tema. .

Aquí hay uno: la lista definitiva de hilos y páginas || = (O Igual)

Si realmente quiere saber qué está pasando, eche un vistazo a la Sección 11.4.2.3 "Asignaciones abreviadas" de la Especificación de borrador de Ruby Language .

Como primera aproximación,

a ||= b

es equivalente a

a || a = b

y no equivalente a

a = a || b

Sin embargo, eso es solo una primera aproximación, especialmente si a no está definido. La semántica también difiere dependiendo de si se trata de una asignación de variable simple, una asignación de método o una asignación de indexación:

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

todos son tratados de manera diferente


Recuerde también que ||= no es una operación atómica y, por lo tanto, no es seguro para subprocesos. Como regla de oro, no lo use para métodos de clase.


Significa or-es igual a. Verifica si el valor de la izquierda está definido, luego use eso. Si no lo es, usa el valor de la derecha. Puede usarlo en Rails para almacenar en caché las variables de instancia en los modelos.

Un ejemplo rápido basado en Rails, donde creamos una función para obtener el usuario que ha iniciado sesión actualmente:

class User > ActiveRecord::Base

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

end

Comprueba si la variable de instancia @current_user está establecida. Si lo es, lo devolverá, con lo que se guardará una llamada de base de datos. Sin embargo, si no está configurado, hacemos la llamada y luego configuramos la variable @current_user para eso. Es una técnica de almacenamiento en caché realmente simple, pero es excelente para cuando se está recuperando la misma variable de instancia en la aplicación varias veces.


como un error común, a || = b no es equivalente a a = a || b, pero lo es, pero se comporta como un || a = b

Pero aquí viene un caso difícil.

Si a no está definido, a || a = 42 genera NameError, mientras que a || = 42 devuelve 42. Por lo tanto, no parecen ser expresiones equivalentes.


a ||= b es lo mismo que decir a = b if a.nil? o a = b unless a

Pero, ¿las 3 opciones muestran el mismo rendimiento? Con Ruby 2.5.1 esto

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

toma 0.099 segundos en mi PC, mientras 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

Toma 0.062 Segundos. Eso es casi un 40% más rápido.

y luego también tenemos:

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

que lleva 0.166 Segundos.

No es que esto tenga un impacto significativo en el rendimiento en general, pero si necesita ese último bit de optimización, entonces considere este resultado. Por cierto: a = 1 unless a sea ​​más fácil de leer para el principiante, se explica por sí mismo.

Nota 1: la razón para repetir la línea de asignación varias veces es reducir la sobrecarga del bucle en el tiempo medido.

Nota 2: Los resultados son similares si hago a=nil nil antes de cada asignación.


unless x x = y end

a menos que x tenga un valor (no es nulo o falso), establézcalo igual a y

es equivalente a

x ||= y


||= se llama un operador de asignación condicional.

Básicamente funciona como = pero con la excepción de que si una variable ya ha sido asignada, no hará nada.

Primer ejemplo:

x ||= 10

Segundo ejemplo:

x = 20
x ||= 10

En el primer ejemplo, x ahora es igual a 10. Sin embargo, en el segundo ejemplo, x ya está definido como 20. Por lo tanto, el operador condicional no tiene ningún efecto. x sigue siendo 20 después de ejecutar x ||= 10 .


a ||= b

es equivalente a

a || a = b

y no

a = a || b

debido a la situación en la que se define un hash con un valor predeterminado (el hash devolverá el valor predeterminado para cualquier clave no definida)

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

si utiliza:

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

a sigue siendo

{}

Pero cuando lo escribes así:

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

a se convierte en:

{10 => true}

porque ha asignado el valor de sí mismo en la clave 10 , que por defecto es verdadero, por lo que ahora el hash se define para la clave 10 , en lugar de nunca realizar la asignación en primer lugar.


b = 5
a ||= b

Esto se traduce en:

a = a || b

Cuál podría ser

a = nil || 5

así que finalmente

a = 5

Ahora si vuelves a llamar a esto:

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

b = 6

Ahora si vuelves a llamar a esto:

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

Si observa, el valor b no se asignará a a . Todavía tendrá un 5 .

Es un patrón de memorización que se utiliza en Ruby para acelerar los accesores.

def users
  @users ||= User.all
end

Esto básicamente se traduce en:

@users = @users || User.all

Así que harás una llamada a la base de datos la primera vez que llames a este método.

Las llamadas futuras a este método solo devolverán el valor de la variable de instancia @users .


x ||= y

es

x || x = y

"si x es falso o no definido, entonces x apunta a y"


Básicamente,


x ||= y significa

si x tiene algún valor, déjelo solo y no cambie el valor; de lo contrario, establezca x en y .





operators