¿Cuál es el punto de retorno en Ruby?

79

¿Cuál es la diferencia entre returny simplemente poner una variable como la siguiente:

sin retorno

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  mood
end

regreso

def write_code(number_of_errors)
  if number_of_errors > 1
    mood =  "Ask me later"
  else
    mood = puts "No Problem"
  end  
  return mood
end
thenengah
fuente

Respuestas:

118

return te permite salir temprano:

def write_code(number_of_errors)
  return "No problem" if number_of_errors == 0
  badness = compute_badness(number_of_errors)
  "WHAT?!  Badness = #{badness}."
end

Si number_of_errors == 0, entonces "No problem"será devuelto inmediatamente. Sin embargo, al final de un método, es innecesario, como observó.


Editar: para demostrar que returnsale inmediatamente, considere esta función:

def last_name(name)
  return nil unless name
  name.split(/\s+/)[-1]
end

Si llama a esta función como last_name("Antal S-Z"), volverá "S-Z". Si lo llama como last_name(nil), regresa nil. Si return no abortaba inmediatamente, intentaría ejecutarse nil.split(/\s+/)[-1], lo que arrojaría un error.

Antal Spector-Zabusky
fuente
ok, buen ejemplo. así que return almacena el valor de retorno pero deja que se ejecute el resto del método. No puedo esperar para usarlo.
thenengah
4
No, al revés: sale return inmediatamente del método. Si piensa en ese ejemplo, no sería útil calcular la maldad si sabe que todo está bien. Editaré mi respuesta para que quede más claro.
Antal Spector-Zabusky
8
Puede usar return, breaketc. sin parámetro; regresarán nilpor defecto.
Nakilon
38

Usar "return" es innecesario si es la última línea que se ejecutará en el método, ya que Ruby devuelve automáticamente la última expresión evaluada.

Ni siquiera necesita ese "estado de ánimo" final, ni necesita esas asignaciones en la declaración IF.

def write_code(number_of_errors)
    if number_of_errors > 1
       "ERROR"
    else
       "No Problem"
    end  
end

puts write_code(10)

Salida:

ERROR

danneu
fuente
37
Viniendo de un fondo que no es Ruby, esa salida es definitivamente WTF. :)
Patrick
return puede salir de la ejecución antes de tiempo. Es el trabajo para.
Joe.wang
1
El retorno también puede ser útil para que un método devuelva nulo en lugar de cuál fue la última expresión evaluada, por lo que a veces verá un retorno sin argumento al final de los métodos.
garythegoat
1
@garythegoat: o simplemente puede escribir nil.
Karoly Horvath
4

Utilizo return cuando reviso una lista y quiero salir de la función si algún miembro de la lista cumple con un criterio. Podría lograr esto con una sola declaración como:

list.select{|k| k.meets_criteria}.length == 0

en algunas situaciones, pero

list.each{|k| return false if k.meets_criteria}

es una línea también, con, en mi opinión, cierta flexibilidad adicional. Por ejemplo, el primer ejemplo asume que esta es la única línea del método y que queremos volver desde este punto pase lo que pase. Pero si esta es una prueba para ver si es seguro continuar con el resto del método, el primer ejemplo deberá manejar eso de una manera diferente.

EDITAR:

Para agregar algo de flexibilidad, considere la siguiente línea de código:

list_of_method_names_as_symbols.each{|k| list_of_objects.each{|j| return k if j.send(k)}}

Estoy seguro de que esto se puede lograr, en una línea, sin return, pero no veo cómo.

Pero esta es ahora una línea de código bastante flexible que se puede llamar con cualquier lista de métodos booleanos y una lista de objetos que implementan esos métodos.

EDITAR

Cabe señalar que supongo que esta línea está dentro de un método, no en un bloque.


Pero esta es principalmente una elección de estilo, creo que en la mayoría de las situaciones, puede y posiblemente debería evitar usar return.

filosofia
fuente
breakes aún más útil en estos casos.
Nakilon
4

¡Ruby regresa siempre! la mejor manera es

def write_code(number_of_errors)
  (number_of_errors > 1)? "ERROR" : "No Problem"
end

significa que si number_of_errors> 1 devolverá ERROR; de lo contrario, no hay problema

msroot
fuente
3

Su bonito rubí ofrece esta buena característica de no especificar declaraciones de retorno explícitamente, pero creo que, como estándar de programación, uno siempre debe esforzarse por especificar declaraciones de "retorno" donde sea necesario. Esto ayuda a hacer que el código sea más legible para alguien que proviene de diferentes antecedentes como C ++, Java, PHP, etc. y que está aprendiendo ruby. La declaración "return" no dañará nada, así que ¿por qué omitir la forma convencional y más estándar de regresar de las funciones?

Kush
fuente
4
"Entonces, ¿por qué omitir la forma convencional y más estándar de regresar de funciones" ← porque en Ruby , omitir return es el estándar convencional. Si ve un returncódigo Ruby con un buen estilo, debería estar allí por una razón, como una ruptura temprana . Tratar de aplicar convenciones de estilo de código de un idioma a otro solo hace que sea más difícil incorporar programadores experimentados y mantener su propio estilo de código consistente.
David Moles
Todavía me sorprendo poniendo punto y coma al final de las líneas
gdbj
¿No es el # 2 en el Zen de Ruby, "implícito es mejor que explícito"? ;-)
Mark
1

Una pequeña advertencia para los que vienen de otros idiomas. Digamos que tiene una función como la de OP y utiliza la regla de "última cosa calculada" para establecer su valor de retorno automáticamente:

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
end

y digamos que agrega una declaración de depuración (o registro):

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  puts "### mood = #{mood}"
end

Ahora adivina qué. Has roto tu código porque putsdevuelve nil, que ahora se convierte en el valor de retorno de la función.

La solución es acostumbrarse a poner siempre explícitamente el valor de retorno en la última línea, como lo hizo el OP:

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  puts "### mood = #{mood}"
  mood
end
Tom Hundt
fuente
-1

La unnecesarity de returnen la última línea en función es solo azúcar sintáctico de Ruby. En la mayoría de los lenguajes procedimentales, debe escribir returnen cada función (no nula en C ++).

Nakilon
fuente
3
No lo llamaría azúcar sintáctico ... la característica principal aquí es que casi todo es una expresión . ifdeclaraciones, bloques de declaraciones. Eso es lo que permite esta expresividad.
Karoly Horvath
Estoy de acuerdo con Karoly: no es azúcar sintáctico porque todo es una expresión.
fatuhoku