Czy funkcja powinna mieć tylko jedną instrukcję return?

Czy istnieją dobre powody, dla których lepiej jest mieć tylko jedno polecenie return w funkcji?

A może jest w porządku zwracać z funkcji tak szybko, jak jest to logicznie poprawne, co oznacza, że w funkcji może być wiele poleceń return?

Author: Tim Post, 2008-08-31

30 answers

Często mam kilka stwierdzeń na początku metody, aby powrócić do" łatwych " sytuacji. Na przykład to:

public void DoStuff(Foo foo)
{
    if (foo != null)
    {
        ...
    }
}

... można zrobić bardziej czytelne (IMHO) TAK:

public void DoStuff(Foo foo)
{
    if (foo == null) return;

    ...
}

Więc tak, myślę, że dobrze jest mieć wiele "punktów wyjścia" z funkcji/metody.

 743
Author: Matt Hamilton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-11 20:40:44

Nikt nie wspomniał ani nie zacytował Kod kompletny więc zrobię to.

17.1 return

Zminimalizuj liczbę zwrotów w każdej rutynie . Trudniej zrozumieć rutynę, jeśli czytając ją na dole, nie jesteś świadomy możliwości, że wróciła gdzieś powyżej.

Użyj return, gdy zwiększa czytelność . W niektórych procedurach, gdy już znasz odpowiedź, chcesz natychmiast przywrócić ją do procedury wywołania. Jeśli rutyna jest zdefiniowany w taki sposób, że nie wymaga żadnego czyszczenia, nie zwracanie natychmiast oznacza, że trzeba napisać więcej kodu.

 355
Author: Chris S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-17 10:01:35

Powiedziałbym, że nierozsądne byłoby arbitralne decydowanie o wielu punktach wyjścia, ponieważ uznałem tę technikę za przydatną w praktyce w kółko i w kółko, w rzeczywistości często zmieniałem istniejący kod na wiele punktów wyjścia dla jasności. Możemy porównać dwa podejścia w ten sposób: -

string fooBar(string s, int? i) {
  string ret = "";
  if(!string.IsNullOrEmpty(s) && i != null) {
    var res = someFunction(s, i);

    bool passed = true;
    foreach(var r in res) {
      if(!r.Passed) {
        passed = false;
        break;
      }
    }

    if(passed) {
      // Rest of code...
    }
  }

  return ret;
}

Porównaj to z kodem, gdzie dozwolone jest wiele punktów wyjścia :-

string fooBar(string s, int? i) {
  var ret = "";
  if(string.IsNullOrEmpty(s) || i == null) return null;

  var res = someFunction(s, i);

  foreach(var r in res) {
      if(!r.Passed) return null;
  }

  // Rest of code...

  return ret;
}
Myślę, że to drugie jest znacznie jaśniejsze. Z tego co wiem krytyka wielu punktów wyjścia jest obecnie raczej archaicznym punktem widzenia.
 229
Author: ljs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-06 14:30:57

Obecnie pracuję nad bazą kodową, w której dwie osoby pracujące nad nią ślepo subskrybują teorię "pojedynczego punktu wyjścia" i mogę wam powiedzieć, że z doświadczenia wynika, że jest to straszna, straszna praktyka. To sprawia, że kod jest niezwykle trudny do utrzymania i pokażę Ci dlaczego.

Z teorią "pojedynczego punktu wyjścia", nieuchronnie kończysz z kodem, który wygląda tak:

function()
{
    HRESULT error = S_OK;

    if(SUCCEEDED(Operation1()))
    {
        if(SUCCEEDED(Operation2()))
        {
            if(SUCCEEDED(Operation3()))
            {
                if(SUCCEEDED(Operation4()))
                {
                }
                else
                {
                    error = OPERATION4FAILED;
                }
            }
            else
            {
                error = OPERATION3FAILED;
            }
        }
        else
        {
            error = OPERATION2FAILED;
        }
    }
    else
    {
        error = OPERATION1FAILED;
    }

    return error;
}

To nie tylko sprawia, że kod jest bardzo trudny do naśladowania, ale teraz powiedz później, że musisz iść Cofnij i dodaj operację między 1 A 2. Musisz wciąć prawie całą cholerną funkcję i powodzenia w upewnianiu się, że wszystkie warunki if / else i szelki są odpowiednio dopasowane.

Ta metoda sprawia, że konserwacja kodu jest niezwykle trudna i podatna na błędy.

 191
Author: 17 of 26,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 12:50:37

Programowanie strukturalne mówi, że każda funkcja powinna mieć tylko jedną instrukcję return. Ma to na celu ograniczenie złożoności. Wiele osób, takich jak Martin Fowler, twierdzi, że łatwiej jest pisać funkcje z wieloma instrukcjami return. Przedstawia ten argument w klasycznej refaktoryzacji książce, którą napisał. Działa to dobrze, jeśli zastosujesz się do jego innych rad i napiszesz małe funkcje. Zgadzam się z tym punktem widzenia i tylko ścisłe puryści programowania stosują się do pojedynczych zwraca instrukcje dla każdej funkcji.

 72
Author: cdv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-05 10:56:54

Jak zauważa Kent Beck podczas omawiania klauzul ochronnych w wzorcach implementacji , co sprawia, że procedura ma jeden punkt wejścia i wyjścia ...

" było, aby zapobiec zamieszaniu możliwe podczas skakania do i z wielu lokalizacje w tej samej rutynie. On dobry sens w przypadku zastosowania do FORTRAN lub napisane programy języka asemblera z dużą ilością danych globalnych, gdzie nawet zrozumienie, które stwierdzenia były egzekucja była ciężką pracą ... małymi metodami i przede wszystkim danych lokalnych, jest niepotrzebnie zachowawczy."

Uważam, że funkcja napisana z klauzulami strażniczymi jest o wiele łatwiejsza do naśladowania niż jedna zagnieżdżona Grupa if then else instrukcji.

 62
Author: blank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 09:48:40

W funkcji, która nie ma skutków ubocznych, nie ma dobrego powodu, aby mieć więcej niż jeden zwrot i powinieneś pisać je w stylu funkcjonalnym. W metodzie z efektami ubocznymi rzeczy są bardziej sekwencyjne( indeksowane czasowo), więc piszesz w trybie imperatywnym, używając instrukcji return jako polecenia do zaprzestania wykonywania.

Innymi słowy, jeśli to możliwe, faworyzuj ten styl

return a > 0 ?
  positively(a):
  negatively(a);

Over this

if (a > 0)
  return positively(a);
else
  return negatively(a);

Jeśli znajdziesz się w zapisie kilku warstw zagnieżdżonych warunków, prawdopodobnie istnieje sposób, aby to zmienić, na przykład używając listy predykatów. Jeśli okaże się, że Twoje ifs i els są daleko od siebie składniowo, możesz chcieć podzielić je na mniejsze funkcje. Blok warunkowy, który obejmuje więcej niż ekran pełen tekstu, jest trudny do odczytania.

Nie ma twardej i szybkiej reguły, która ma zastosowanie do każdego języka. Coś takiego jak posiadanie pojedynczego Oświadczenia zwrotnego nie uczyni Twojego kodu dobrym. Ale dobry kod pozwoli Ci pisać swoje funkcje, które sposób.
 61
Author: Apocalisp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-07 18:06:17

Widziałem to w standardach kodowania dla C++, które były zawieszeniem od C, jak jeśli nie masz RAII lub innego automatycznego zarządzania pamięcią, to musisz posprzątać dla każdego powrotu, Co albo oznacza wycinanie i wklejanie czyszczenia lub goto( logicznie to samo, co "w końcu" w językach zarządzanych), z których oba są uważane za złą formę. Jeśli Twoje praktyki polegają na używaniu inteligentnych wskaźników i kolekcji w C++ lub innym automatycznym systemie pamięci, to nie ma mocnego powodu do tego i staje się wszystko o czytelności, a bardziej o ocenie.

 43
Author: Pete Kirkham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-28 08:36:51

Pochylam się nad ideą, że polecenia return w środku funkcji są złe. Możesz użyć funkcji returns, aby zbudować kilka klauzul ochronnych na górze funkcji i oczywiście powiedzieć kompilatorowi, co ma zwrócić na końcu funkcji bez problemu, ale zwroty w środku funkcji mogą być łatwe do pominięcia i mogą sprawić, że funkcja będzie trudniejsza do zinterpretowania.

 40
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-14 19:15:45

Czy istnieją dobre powody, dla których lepiej jest mieć tylko jedno polecenie return w funkcji?

Tak , są:

  • pojedynczy punkt wyjścia daje doskonałe miejsce do potwierdzenia twoich warunków.
  • możliwość umieszczenia punktu przerwania debuggera na jednym zwrocie na końcu funkcji jest często użyteczna.
  • mniej zwrotów oznacza mniejszą złożoność. Kod liniowy jest ogólnie prostszy do zrozumienia.
  • Jeśli próbujesz uprościć funkcja do pojedynczego zwrotu powoduje złożoność, to jest to zachęta do refaktoryzacji do mniejszych, bardziej ogólnych, łatwiejszych do zrozumienia funkcji.
  • Jeśli jesteś w języku bez destruktorów lub jeśli nie używasz RAII, to pojedynczy powrót zmniejsza liczbę miejsc, które musisz posprzątać.
  • Niektóre języki wymagają jednego punktu wyjścia (np. Pascal i Eiffel).

Pytanie jest często stawiane jako fałszywa dychotomia między wielokrotnymi zwrotami lub głęboko zagnieżdżonymi wypowiedziami if. Prawie zawsze istnieje trzecie rozwiązanie, które jest bardzo liniowe (bez głębokiego zagnieżdżania) z tylko jednym punktem wyjścia.

Update: najwyraźniej wytyczne MISRA promują również pojedyncze wyjście.

Żeby było jasne, nie mówię, że to jest zawsze źle mieć wiele zwrotów. Ale biorąc pod uwagę inne równoważne rozwiązania, istnieje wiele dobrych powodów, aby preferować ten z jednym zwrotem.

 38
Author: Adrian McCarthy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:48

Posiadanie pojedynczego punktu wyjścia daje przewagę w debugowaniu, ponieważ pozwala ustawić pojedynczy punkt przerwania na końcu funkcji, aby zobaczyć, jaka wartość faktycznie zostanie zwrócona.

 33
Author: Mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-03 21:58:47

Ogólnie staram się mieć tylko jeden punkt wyjścia z funkcji. Czasem jednak zdarza się, że w efekcie powstaje bardziej złożone ciało funkcyjne niż jest to konieczne, w którym to przypadku lepiej mieć wiele punktów wyjścia. To naprawdę musi być "wezwanie do oceny" w oparciu o wynikającą z tego złożoność, ale celem powinno być jak najmniej punktów wyjścia, bez poświęcania złożoności i zrozumiałości.

 19
Author: Scott Dorman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-08 19:37:01

Nie, ponieważ nie żyjemy już w latach 70. . Jeśli funkcja jest wystarczająco długa, że wiele zwrotów stanowi problem, jest zbyt długa.

(pomijając fakt, że każda funkcja wielowierszowa w języku z wyjątkami i tak będzie miała wiele punktów wyjścia.)

 14
Author: Ben Lings,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-14 19:31:14

Preferuję Pojedyncze Wyjście, chyba że to naprawdę komplikuje sprawy. Odkryłem, że w niektórych przypadkach wiele istniejących punktów może maskować inne bardziej znaczące problemy projektowe: {]}

public void DoStuff(Foo foo)
{
    if (foo == null) return;
}

Po obejrzeniu tego kodu od razu zapytałbym:

  • czy " foo " jest kiedykolwiek zerowe?
  • jeśli tak, to ilu klientów ' DoStuff 'wywołuje funkcję z null'foo'?

W zależności od odpowiedzi na te pytania może być tak, że

  1. czek jest bezcelowy jak to nigdy nie jest prawdą (tj. powinno to być twierdzenie)
  2. sprawdzanie jest bardzo rzadko prawdziwe, więc może lepiej zmienić te konkretne funkcje wywołujące, ponieważ i tak powinny one podjąć inne działania.

W obu powyższych przypadkach kod może być przerobiony z twierdzeniem, aby upewnić się, że 'foo' nigdy nie jest równe null i odpowiednie wywołania zostały zmienione.

Istnieją dwa inne powody (specyficzne chyba dla kodu C++), w których wielokrotne istnienie może mieć negatywny wpływ. Są to rozmiar kodu i optymalizacja kompilatora.

Obiekt nie-POD C++ znajdujący się na wyjściu funkcji będzie miał wywołany Destruktor. Jeśli istnieje kilka poleceń return, może się zdarzyć, że w zasięgu są różne obiekty, a więc lista destruktorów do wywołania będzie inna. Kompilator musi zatem wygenerować kod dla każdej instrukcji return:

void foo (int i, int j) {
  A a;
  if (i > 0) {
     B b;
     return ;   // Call dtor for 'b' followed by 'a'
  }
  if (i == j) {
     C c;
     B b;
     return ;   // Call dtor for 'b', 'c' and then 'a'
  }
  return 'a'    // Call dtor for 'a'
}

Jeśli rozmiar kodu jest problemem - to może być coś wartego unikanie.

Drugi problem dotyczy "nazwanej optymalizacji wartości zwrotnej" (aka Copy Elision, ISO C++ '03 12.8/15). C++ pozwala implementacji pominąć wywołanie konstruktora kopiującego, jeśli może:

A foo () {
  A a1;
  // do something
  return a1;
}

void bar () {
  A a2 ( foo() );
}

Po prostu biorąc kod tak jak jest, obiekt ' A1 'jest skonstruowany w' foo', a następnie jego kopia zostanie wywołana do skonstruowania 'A2'. Jednak copy elision pozwala kompilatorowi konstruować 'a1' w tym samym miejscu na stosie co 'a2'. Nie ma więc potrzeby "kopiowania" obiektu gdy funkcja powróci.

Wiele punktów wyjścia komplikuje pracę kompilatora próbując to wykryć, a przynajmniej dla stosunkowo niedawnej wersji VC++ optymalizacja nie miała miejsca tam, gdzie ciało funkcji miało wiele zwrotów. Zobacz nazwane Optymalizacja wartości zwrotnej w Visual C++ 2005 aby uzyskać więcej szczegółów.

 14
Author: Richard Corden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-11 20:42:08

Posiadanie pojedynczego punktu wyjścia zmniejsza złożoność Cyklomatyczną i dlatego w teorii zmniejsza prawdopodobieństwo wprowadzenia błędów do kodu, gdy go zmienisz. Praktyka sugeruje jednak, że potrzebne jest bardziej pragmatyczne podejście. Dlatego staram się mieć jeden punkt wyjścia, ale pozwolę, aby mój kod miał kilka, jeśli jest bardziej czytelny.

 11
Author: John Channing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-02 21:17:52

Zmuszam się do użycia tylko jednego return stwierdzenia, ponieważ w pewnym sensie wygeneruje ono zapach kodu. Pozwól mi wyjaśnić:

function isCorrect($param1, $param2, $param3) {
    $toret = false;
    if ($param1 != $param2) {
        if ($param1 == ($param3 * 2)) {
            if ($param2 == ($param3 / 3)) {
                $toret = true;
            } else {
                $error = 'Error 3';
            }
        } else {
            $error = 'Error 2';
        }
    } else {
        $error = 'Error 1';
    }
    return $toret;
}

(warunki są arbritary...)

Im więcej warunków, tym większa jest funkcja, tym trudniej ją odczytać. Więc jeśli jesteś dostrojony do zapachu kodu, zdasz sobie z tego sprawę i chcesz go refaktorować. Dwa możliwe rozwiązania to:

  • wiele zwrotów
  • Refaktoryzacja w osobne funkcje

Wiele Zwrotów

function isCorrect($param1, $param2, $param3) {
    if ($param1 == $param2)       { $error = 'Error 1'; return false; }
    if ($param1 != ($param3 * 2)) { $error = 'Error 2'; return false; }
    if ($param2 != ($param3 / 3)) { $error = 'Error 3'; return false; }
    return true;
}

Oddzielne Funkcje

function isEqual($param1, $param2) {
    return $param1 == $param2;
}

function isDouble($param1, $param2) {
    return $param1 == ($param2 * 2);
}

function isThird($param1, $param2) {
    return $param1 == ($param2 / 3);
}

function isCorrect($param1, $param2, $param3) {
    return !isEqual($param1, $param2)
        && isDouble($param1, $param3)
        && isThird($param2, $param3);
}

Oczywiście, jest ona dłuższa i trochę brudna, ale w procesie refaktoryzacji funkcji w ten sposób, mamy

  • stworzył szereg funkcji wielokrotnego użytku,
  • uczyniła funkcję bardziej czytelną dla człowieka, a
  • funkcje koncentrują się na tym, dlaczego wartości są poprawne.
 11
Author: Jrgns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-30 09:57:18

Powiedziałbym, że powinieneś mieć tyle, ile potrzebujesz, lub takie, które czynią kod czystszym(np. klauzule ochronne).

Osobiście nigdy nie słyszałem/nie widziałem żadnych "najlepszych praktyk" mówiących, że powinieneś mieć tylko jedno oświadczenie zwrotne.

W większości przypadków mam tendencję do jak najszybszego wyjścia z funkcji na podstawie ścieżki logicznej(klauzule strażnicze są tego doskonałym przykładem).

 10
Author: Rob Cooper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 09:30:18

Uważam, że wielokrotne Zwroty są zazwyczaj dobre(w kodzie, który piszę w C#). Styl jednokrotnego powrotu jest utrzymywany z C. ale prawdopodobnie nie kodujesz w C.

Nie ma prawa wymagającego tylko jednego punktu wyjścia dla metody we wszystkich językach programowania . Niektórzy podkreślają wyższość tego stylu, a czasami podnoszą go do "zasady" lub "prawa", ale przekonanie to nie jest poparte żadnymi dowodami lub badaniami.

Więcej niż jeden styl return może być zły nawyk w kodzie C, gdzie zasoby muszą być wyraźnie dealokowane, ale języki takie jak Java, C#, Python lub JavaScript, które mają konstrukcje takie jak automatyczne usuwanie śmieci i bloki try..finally (i bloki using W C#), a ten argument nie ma zastosowania - w tych językach bardzo rzadko trzeba scentralizować ręczną dealokację zasobów.

Są przypadki, w których pojedynczy zwrot jest bardziej czytelny, i przypadki, w których nie jest. sprawdź, czy zmniejsza liczbę linii kodu, sprawia, że logika jest bardziej przejrzysta lub zmniejsza liczbę nawiasów klamrowych i wcięć lub zmiennych tymczasowych.

Dlatego używaj tyle zwrotów, ile odpowiada Twojej wrażliwości artystycznej, ponieważ jest to kwestia układu i czytelności, a nie techniczna.

Mówiłem o tym na moim blogu.

 10
Author: Anthony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-04 10:16:38

Są dobre rzeczy do powiedzenia o posiadaniu jednego punktu wyjścia, tak jak są złe rzeczy do powiedzenia o nieuniknionym "strzałce" programowaniu, które powoduje.

Jeśli używam wielu punktów wyjścia podczas walidacji wejścia lub alokacji zasobów, staram się umieścić wszystkie "wyjścia błędów" bardzo wyraźnie na górze funkcji.

Zarówno Spartan programowanie artykuł "SSDSLPedia" i punkt wyjścia pojedynczej funkcji artykuł "Portland Pattern Wiki repozytorium " ma kilka wnikliwych argumentów na ten temat. Ponadto, oczywiście, jest ten post do rozważenia.

Jeśli naprawdę chcesz pojedynczy punkt wyjścia (w dowolnym języku bez wyjątku), na przykład, aby zwolnić zasoby w jednym miejscu, uważam staranne zastosowanie goto za dobre; patrz na przykład ten dość wymyślny przykład (skompresowany, aby zapisać nieruchomość ekranu):

int f(int y) {
    int value = -1;
    void *data = NULL;

    if (y < 0)
        goto clean;

    if ((data = malloc(123)) == NULL)
        goto clean;

    /* More code */

    value = 1;
clean:
   free(data);
   return value;
}

Osobiście, ogólnie rzecz biorąc, nie lubię programowania arrow bardziej niż wiele punktów wyjścia, chociaż oba są przydatne, gdy są prawidłowo stosowane. Najlepszym, oczywiście, jest skonstruowanie programu tak, aby nie wymagał żadnego. Rozbicie funkcji na wiele kawałków zazwyczaj pomaga:) [5]}

Chociaż kiedy to robię, i tak kończę z wieloma punktami wyjścia, jak w tym przykładzie, gdzie jakaś większa funkcja została podzielona na kilka mniejszych funkcji:

int g(int y) {
  value = 0;

  if ((value = g0(y, value)) == -1)
    return -1;

  if ((value = g1(y, value)) == -1)
    return -1;

  return g2(y, value);
}

W zależności od projektu lub wytycznych kodowania, większość kodu płyty kotłowej może być zastąpiony przez makra. Na marginesie, rozbicie go w ten sposób sprawia, że funkcje g0, g1, g2 są bardzo łatwe do przetestowania indywidualnie.

Oczywiście, w języku OO i z włączoną obsługą WYJĄTKÓW, nie używałbym takich instrukcji if-(lub w ogóle, gdybym mógł to ujść na sucho z niewielkim wysiłkiem), a kod byłby o wiele bardziej prosty. I nie-arowy. A większość niekończących się zwrotów to prawdopodobnie wyjątki.

W skrócie;

  • niewiele zwrotów jest lepszych od wielu returns
  • więcej niż jeden zwrot jest lepszy niż wielkie strzały, a klauzule ochronne są ogólnie ok.
  • wyjątki mogą / powinny prawdopodobnie zastąpić większość "klauzul ochronnych", jeśli to możliwe.
 10
Author: Henrik Gustafsson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-11 20:44:19

Wiesz przysłowie - piękno jest w oczach patrzącego .

Niektórzy przeklinają przez NetBeans a niektórzy przez IntelliJ IDEA , Niektórzy przez Python a niektórzy przez PHP .

W niektórych sklepach możesz stracić pracę, jeśli nalegasz na to:

public void hello()
{
   if (....)
   {
      ....
   }
}

Pytanie dotyczy widoczności i łatwości konserwacji.

Jestem uzależniony od używania algebry Boole ' a do redukcji i uproszczenia logiki oraz używania maszyn stanowych. Były jednak dawni koledzy, którzy uważali, że moje wykorzystanie" technik matematycznych " w kodowaniu jest nieodpowiednie, ponieważ nie byłoby widoczne i możliwe do utrzymania. A to byłaby zła praktyka. Przepraszam ludzi, techniki, które stosuję są dla mnie bardzo widoczne i możliwe do utrzymania - bo gdy wrócę do kodu pół roku później, zrozumiałbym kod wyraźnie, raczej widząc bałagan przysłowiowego spaghetti.

Hej kolego (jak mawiał były klient) rób co chcesz, o ile wiesz jak to naprawić kiedy musisz to naprawić.

Pamiętam, że 20 lat temu zwolniono mojego kolegę za stosowanie strategii zwinnego rozwoju (agile development). Miał skrupulatny Plan. Ale jego menedżer krzyczał na niego "nie możesz stopniowo udostępniać funkcji użytkownikom! Musisz trzymać się wodospadu ."Jego odpowiedź dla menedżera była taka, że stopniowy rozwój będzie bardziej precyzyjny do potrzeb klienta. Wierzył w rozwój dla klientów potrzeb, ale menedżer wierzył w kodowanie do "wymagań klienta".

Jesteśmy często winni łamania normalizacji danych, MVP i MVC granice. Inline zamiast konstruować funkcję. Idziemy na skróty.

Osobiście uważam, że PHP jest złą praktyką, ale co ja wiem. Wszystkie argumenty teoretyczne sprowadza się do próby spełnienia jednego zbioru reguł

Jakość = precyzja, konserwacja oraz rentowność.

Wszystkie inne zasady znikają w tle. I oczywiście zasada ta nigdy nie zanika:

Lenistwo jest cnotą dobra programista.
 9
Author: Blessed Geek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-11 20:44:58

Skłaniam się ku użyciu klauzul ochronnych, aby wrócić wcześniej, a w przeciwnym razie wyjść na końcu metody. Reguła single entry and exit ma znaczenie historyczne i była szczególnie pomocna w przypadku kodu starszego typu, który liczył 10 stron A4 dla jednej metody C++ z wieloma zwrotami (i wieloma wadami). Ostatnio przyjętą dobrą praktyką jest utrzymywanie metod małych, co sprawia, że wiele wyjść jest mniej impedancji do zrozumienia. W poniższym przykładzie Kronoz skopiowanym z góry, pytanie, co występuje w / / reszta kodu...?:

void string fooBar(string s, int? i) {

  if(string.IsNullOrEmpty(s) || i == null) return null;

  var res = someFunction(s, i);

  foreach(var r in res) {
      if(!r.Passed) return null;
  }

  // Rest of code...

  return ret;
}

Zdaję sobie sprawę, że przykład jest nieco wymyślony, ale chciałbym pokusić się o refaktoryzację pętli foreach W instrukcję LINQ, która może być następnie uznana za klauzulę ochronną. Ponownie, w wymyślonym przykładzie intencja kodu nie jest widoczna i someFunction () może mieć jakiś inny efekt uboczny lub wynik może być użyty w // reszta kodu....

if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;

Dając następujące refakturowane funkcja:

void string fooBar(string s, int? i) {

  if (string.IsNullOrEmpty(s) || i == null) return null;
  if (someFunction(s, i).Any(r => !r.Passed)) return null;

  // Rest of code...

  return ret;
}
 9
Author: David Clarke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-11 20:46:44

Jeden dobry powód, który mogę wymyślić, to Konserwacja kodu: masz jeden punkt wyjścia. Jeśli chcesz zmienić format wyniku,..., jest po prostu znacznie prostsze do wdrożenia. Ponadto, do debugowania, możesz po prostu umieścić tam punkt przerwania:)

Powiedziawszy to, musiałem kiedyś pracować w bibliotece, w której standardy kodowania narzucały 'jedną deklarację powrotu na funkcję' i uznałem to za dość trudne. Piszę dużo kodu do obliczeń numerycznych i często są "przypadki szczególne", więc kod okazał się dość trudny do naśladowania...

 7
Author: OysterD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 09:31:16

Wiele punktów wyjścia jest w porządku dla wystarczająco małych funkcji - to znaczy funkcji, która może być wyświetlana na jednej długości ekranu w całości. Jeśli długa funkcja również zawiera wiele punktów wyjścia, jest to znak, że funkcja może być pocięta dalej.

To powiedziaĹ 'o, Ĺźe unikam funkcji wielokrotnego wyjĹ" cia chyba Ĺźe jest to absolutnie konieczne. Odczuwałem ból błędów, które są spowodowane pewnym bezpańskim powrotem w jakiejś niejasnej linii w bardziej złożonych funkcjach.

 7
Author: Jon Limjap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 13:38:46

Pracowałem z okropnymi standardami kodowania, które wymusiły na Tobie pojedynczą ścieżkę wyjścia, a wynik jest prawie zawsze niestrukturalny, jeśli funkcja nie jest trywialna - kończysz z wieloma przerwami i kontynuujesz, które po prostu przeszkadzają.

 6
Author: Phil Bennett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 09:39:25

Pojedynczy punkt wyjścia - wszystkie inne rzeczy równe-sprawia, że kod jest znacznie bardziej czytelny. Ale jest pewien haczyk: popular construction

resulttype res;
if if if...
return res;

Jest podróbką, "res=" nie jest dużo lepsze niż"return". Ma pojedynczą instrukcję return, ale wiele punktów, w których funkcja faktycznie się kończy.

Jeśli masz funkcję z wieloma zwrotami (lub "res="s), często dobrym pomysłem jest rozbicie jej na kilka mniejszych funkcji z jednym punktem wyjścia.

 6
Author: ima,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-11 07:39:18

Moją zwyczajową zasadą jest posiadanie tylko jednej instrukcji return na końcu funkcji, chyba że złożoność kodu zostanie znacznie zmniejszona przez dodanie kolejnych. W rzeczywistości jestem raczej fanem Eiffla, który wymusza jedyną regułę powrotu przez brak instrukcji powrotu(istnieje tylko automatycznie utworzona zmienna 'result', aby umieścić swój wynik).

Z pewnością są przypadki, w których kod może być jaśniejszy z wieloma zwrotami, niż wersja bez nich byłaby oczywista. Można by argumentować, że więcej przeróbka jest potrzebna, jeśli masz funkcję, która jest zbyt złożona, aby była zrozumiała bez wielu zwrotów, ale czasami dobrze jest być pragmatycznym w takich sprawach.

 6
Author: Matt Sheppard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-11 07:48:45

Jeśli otrzymasz więcej niż kilka zwrotów, może być coś nie tak z Twoim kodem. W przeciwnym razie zgodziłbym się, że czasami miło jest być w stanie wrócić z wielu miejsc w podprogramie, zwłaszcza gdy czyni to kod czystszym.

Perl 6: Zły Przykład

sub Int_to_String( Int i ){
  given( i ){
    when 0 { return "zero" }
    when 1 { return "one" }
    when 2 { return "two" }
    when 3 { return "three" }
    when 4 { return "four" }
    ...
    default { return undef }
  }
}

Byłoby lepiej napisane tak

Perl 6: Dobry Przykład

@Int_to_String = qw{
  zero
  one
  two
  three
  four
  ...
}
sub Int_to_String( Int i ){
  return undef if i < 0;
  return undef unless i < @Int_to_String.length;
  return @Int_to_String[i]
}

Uwaga To był tylko szybki przykład

 5
Author: Brad Gilbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 15:53:45

Głosuję za pojedynczym powrotem na końcu jako wytyczna. Pomaga to w obsłudze wspólnego czyszczenia kodu ... Na przykład, spójrz na poniższy kod ...

void ProcessMyFile (char *szFileName)
{
   FILE *fp = NULL;
   char *pbyBuffer = NULL:

   do {

      fp = fopen (szFileName, "r");

      if (NULL == fp) {

         break;
      }

      pbyBuffer = malloc (__SOME__SIZE___);

      if (NULL == pbyBuffer) {

         break;
      }

      /*** Do some processing with file ***/

   } while (0);

   if (pbyBuffer) {

      free (pbyBuffer);
   }

   if (fp) {

      fclose (fp);
   }
}
 5
Author: Alphaneo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-11 20:47:36

Jest to prawdopodobnie nietypowa perspektywa, ale myślę, że każdy, kto wierzy, że wiele poleceń return powinno być preferowanych, nigdy nie musiał używać debuggera na mikroprocesorze, który obsługuje tylko 4 sprzętowe punkty przerwania. ;-)

Podczas gdy problemy z "kodem strzałek" są całkowicie poprawne, jeden problem, który wydaje się znikać, gdy używasz wielu instrukcji return, jest w sytuacji, gdy używasz debuggera. Nie masz wygodnej pozycji catch-all, aby umieścić punkt przerwania gwarancja, że zobaczysz wyjście, a co za tym idzie warunek powrotu.

 4
Author: Andrew Edgecombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 23:47:34

Im więcej instrukcji return masz w funkcji, tym większa złożoność tej jednej metody. Jeśli zastanawiasz się, czy masz zbyt wiele instrukcji return, możesz zadać sobie pytanie, Czy masz zbyt wiele linii kodu w tej funkcji.

Ale nie, nie ma nic złego w jednej / wielu instrukcjach return. W niektórych językach jest to lepsza praktyka (C++) niż w innych (C).

 4
Author: hazzen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-27 09:56:54