jaki jest sens zwrotu w Rubim?

79

Jaka jest różnica między returna zwykłym umieszczeniem zmiennej, takiej jak ta:

bez powrotu

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

powrót

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
źródło

Odpowiedzi:

118

return pozwala na wczesne wyrwanie:

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

Jeśli number_of_errors == 0, to "No problem"zostanie natychmiast zwrócony. Jak zauważyłeś, pod koniec metody jest ona jednak niepotrzebna.


Edytować: Aby wykazać, że returnkończy się natychmiast, rozważ tę funkcję:

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

Jeśli nazwiesz tę funkcję jako last_name("Antal S-Z"), zwróci "S-Z". Jeśli nazwiesz to jako last_name(nil), to wraca nil. Jeśli return nie przerwał natychmiast, spróbowałby wykonać nil.split(/\s+/)[-1], co spowodowałoby błąd.

Antal Spector-Zabusky
źródło
ok, dobry przykład. więc return przechowuje wartość zwracaną, ale pozwala na wykonanie reszty metody. Nie mogę się doczekać, aby go użyć.
thenengah,
4
Nie, na odwrót: return natychmiast wychodzi z metody. Jeśli pomyślisz o tym przykładzie, obliczanie zła nie byłoby przydatne, gdybyś wiedział, że wszystko jest w porządku. Zmienię odpowiedź, aby była jaśniejsza.
Antal Spector-Zabusky
8
Można użyć return, breakitd. Bez parametru - oni powrócić nildomyślnie.
Nakilon,
38

Używanie „return” jest niepotrzebne, jeśli jest to ostatnia linia do wykonania w metodzie, ponieważ Ruby automatycznie zwraca ostatnie obliczone wyrażenie.

Nie potrzebujesz nawet tego końcowego „nastroju”, ani nie potrzebujesz tych zadań w instrukcji IF.

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

puts write_code(10)

Wynik:

BŁĄD

danneu
źródło
37
Pochodząc z tła innego niż Ruby, ten wynik jest zdecydowanie WTF. :)
Patrick
return może zakończyć wykonywanie wcześniej. To jest praca dla.
Joe.wang
1
Zwrot może być również pomocny w przypadku zwracania przez metodę wartości nil zamiast tego, co było ostatnim oszacowanym wyrażeniem, więc czasami zobaczysz zwrot bez argumentów na końcu metod.
garythegoat
1
@garythegoat: lub po prostu napisz nil.
Karoly Horvath
4

Używam powrotu, gdy przeglądam listę i chcę wyjść z funkcji, jeśli którykolwiek członek listy spełnia kryteria. Mogę to osiągnąć za pomocą jednego stwierdzenia, takiego jak:

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

w niektórych sytuacjach, ale

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

to też jedna kwestia - z pewną dodatkową elastycznością. Na przykład w pierwszym przykładzie założono, że jest to jedyna linia w metodzie i chcemy wrócić z tego punktu bez względu na wszystko. Ale jeśli jest to test mający na celu sprawdzenie, czy można bezpiecznie przejść do pozostałej części metody, pierwszy przykład będzie musiał potraktować to w inny sposób.

EDYTOWAĆ:

Aby zwiększyć elastyczność, rozważ następujący wiersz kodu:

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

Jestem pewien, że można to osiągnąć w jednej linii, bez return, ale nie wiem, jak to zrobić.

Ale teraz jest to dość elastyczny wiersz kodu, który można wywołać za pomocą dowolnej listy metod logicznych i listy obiektów, które implementują te metody.

EDYTOWAĆ

Należy zauważyć, że zakładam, że ta linia znajduje się wewnątrz metody, a nie bloku.


Ale jest to głównie wybór stylistyczny, myślę, że w większości sytuacji można i prawdopodobnie należy unikać używania return.

philosodad
źródło
breakjest jeszcze bardziej przydatne w takich przypadkach.
Nakilon,
4

Ruby zawsze powraca! najlepszy sposób

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

oznacza to, że jeśli number_of_errors> 1 zwróci ERROR w przeciwnym razie nie ma problemu

msroot
źródło
3

Jego ładny ruby ​​daje tę dobrą cechę, że nie podaje jawnie instrukcji return, ale po prostu uważam, że jako standard programowania zawsze należy dążyć do określenia instrukcji „return” tam, gdzie jest to wymagane. Pomaga to w uczynieniu kodu bardziej czytelnym dla kogoś, kto pochodzi z różnych środowisk, takich jak C ++, Java, PHP itp. I uczy się języka Ruby. Instrukcja „return” niczego nie zaszkodzi, więc po co pomijać konwencjonalny i bardziej standardowy sposób powrotu z funkcji.

Kush
źródło
4
"więc po co pomijać konwencjonalny i bardziej standardowy sposób powrotu z funkcji" ←, ponieważ w Rubim pomijanie return jest standardem konwencjonalnym. Jeśli widzisz returndobrze wystylizowany kod Ruby, powinien tam być z jakiegoś powodu, na przykład wczesnego przerwania . Próba zastosowania konwencji stylu kodu z jednego języka do drugiego utrudnia zatrudnienie doświadczonych programistów i zachowanie spójności własnego stylu kodu.
David Moles
wciąż
łapię się na umieszczaniu średników
Czy nie jest to drugie miejsce w Zen Ruby: „ukryte jest lepsze niż jawne”? ;-)
Mark
1

Mała uwaga dla osób pochodzących z innych języków. Powiedzmy, że masz funkcję taką jak OP i używasz reguły „ostatnia rzecz obliczona”, aby automagicznie ustawić wartość zwracaną:

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

i powiedzmy, że dodajesz instrukcję debugowania (lub logowania):

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

A teraz zgadnij co. Twój kod został uszkodzony, ponieważ putszwraca nil, które teraz staje się wartością zwracaną przez funkcję.

Rozwiązaniem jest przyzwyczajenie się do zawsze jawnego umieszczania wartości zwracanej w ostatniej linii, tak jak zrobił to PO:

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
źródło
-1

Niepotrzebność returnostatniej linii funkcji jest po prostu cukrem składniowym Rubiego. W większości języków proceduralnych musisz pisać returnw każdej funkcji (nieważnej w C ++).

Nakilon
źródło
3
Nie nazwałbym tego cukrem syntaktycznym ... podstawową cechą tutaj jest to, że prawie wszystko jest wyrażeniem . ifinstrukcje, bloki instrukcji. To właśnie pozwala na taką ekspresję.
Karoly Horvath
Zgadzam się z Karolym - to nie jest cukier syntaktyczny, bo wszystko jest wyrażeniem.
fatuhoku