Istota, jeśli pytanie brzmi: „Jak zwrócić dwie niepowiązane informacje z metody, która zwraca jedną liczbę całkowitą? Nigdy nie chcę sprawdzać moich zwracanych wartości, a wartości null są złe, nie używaj ich”.
Spójrzmy na to, co chcesz przekazać. Zdajesz uzasadnienie int lub non-int, dlaczego nie możesz podać int. Pytanie zapewnia, że będą tylko dwa powody, ale każdy, kto kiedykolwiek wyliczył enum, wie, że każda lista będzie rosła. Określenie innych uzasadnień ma sens.
Początkowo wydaje się, że może to być dobry powód do zgłoszenia wyjątku.
Jeśli chcesz powiedzieć dzwoniącemu coś wyjątkowego, co nie występuje w typie zwracanym, wyjątki są często odpowiednim systemem: wyjątki dotyczą nie tylko stanów błędów i pozwalają na zwrócenie wielu kontekstów i uzasadnień wyjaśniających, dlaczego tak po prostu możesz to jest dzisiaj.
I to jest TYLKO system, który pozwala na zwrócenie gwarantowanych poprawnych liczb całkowitych i gwarantuje, że każdy operator int i metoda, która przyjmuje liczby ints, może zaakceptować wartość zwracaną tej metody bez konieczności sprawdzania nieprawidłowych wartości, takich jak null lub magiczne wartości.
Ale wyjątki są tak naprawdę tylko właściwym rozwiązaniem, jeśli, jak sama nazwa wskazuje, jest to wyjątkowy przypadek, a nie normalny sposób prowadzenia działalności.
A try / catch i handler to tak samo płyta kontrolna jak kontrola zerowa, co było przede wszystkim przedmiotem sprzeciwu.
A jeśli dzwoniący nie zawiera try / catch, wówczas dzwoniący musi to zrobić i tak dalej.
Naiwnym drugim przejściem jest powiedzenie „To pomiar. Negatywne pomiary odległości są mało prawdopodobne”. Więc dla niektórych pomiarów Y możesz mieć po prostu stałe dla
- -1 = nieznany,
- -2 = niemożliwy do zmierzenia,
- -3 = odmówił odpowiedzi,
- -4 = znany, ale poufny,
- -5 = zmienia się w zależności od fazy księżyca, patrz tabela 5a,
- -6 = czterowymiarowe, wymiary podane w tytule,
- -7 = błąd odczytu systemu plików,
- -8 = zarezerwowane do wykorzystania w przyszłości,
- -9 = kwadrat / sześcienny, więc Y jest takie samo jak X,
- -10 = to ekran monitora, więc nie używaj pomiarów X, Y: użyj X jako przekątnej ekranu,
- -11 = zapisał pomiary na odwrocie paragonu i został sprany do nieczytelności, ale myślę, że był to 5 lub 17,
- -12 = ... masz pomysł.
Tak dzieje się w wielu starych systemach C, a nawet w nowoczesnych systemach, w których istnieje rzeczywiste ograniczenie int, a nie można go owinąć w strukturę lub monadę jakiegoś typu.
Jeśli pomiary mogą być ujemne, to po prostu powiększasz typ danych (np. Long int) i masz magiczne wartości wyższe niż zakres int, i idealnie zaczynasz od pewnej wartości, która będzie wyraźnie widoczna w debuggerze.
Istnieją jednak dobre powody, aby mieć je jako osobną zmienną, a nie tylko magiczne liczby. Na przykład ścisłe pisanie, łatwość konserwacji i zgodność z oczekiwaniami.
W naszej trzeciej próbie przyglądamy się zatem przypadkom, w których normalnym kierunkiem działalności jest posiadanie wartości innych niż int. Na przykład, jeśli zbiór tych wartości może zawierać wiele pozycji niecałkowitych. Oznacza to, że procedura obsługi wyjątków może być niewłaściwa.
W takim przypadku wygląda to dobrze na strukturę, która przechodzi przez int, i uzasadnienie. Ponownie, to uzasadnienie może być po prostu stałą jak powyżej, ale zamiast trzymać oba w tej samej int, przechowujesz je jako odrębne części struktury. Początkowo mamy zasadę, że jeśli zostanie ustawione uzasadnienie, int nie zostanie ustawione. Ale nie jesteśmy już przywiązani do tej zasady; w razie potrzeby możemy podać uzasadnienie również dla prawidłowych liczb.
Tak czy inaczej, za każdym razem, gdy go wywołujesz, nadal potrzebujesz szablonu, aby przetestować uzasadnienie, aby sprawdzić, czy int jest poprawny, a następnie wyciągnij i użyj części int, jeśli uzasadnienie na to pozwala.
W tym miejscu musisz zbadać swoje uzasadnienie „nie używaj null”.
Podobnie jak wyjątki, null ma oznaczać wyjątkowy stan.
Jeśli osoba dzwoniąca wywołuje tę metodę i całkowicie ignoruje „uzasadnienie” części struktury, oczekując liczby bez obsługi błędów, i otrzymuje zero, wówczas zniesie zero jako liczbę i będzie źle. Jeśli otrzyma magiczną liczbę, potraktuje to jako liczbę i pomyli się. Ale jeśli przyjmie wartość zerową, przewróci się , jak powinno, to cholernie dobrze.
Tak więc za każdym razem, gdy wywołujesz tę metodę, musisz sprawdzać jej wartość zwracaną, jednak obsługujesz niepoprawne wartości, czy to w paśmie, czy poza pasmem, spróbuj / złap, sprawdzając strukturę pod kątem komponentu „racjonalnego”, sprawdzając int dla magicznej liczby lub sprawdzanie int dla zerowej ...
Alternatywą, aby poradzić sobie z mnożeniem wyniku, który może zawierać niepoprawną liczbę całkowitą i uzasadnienie, takie jak „Mój pies zjadł ten pomiar”, jest przeciążenie operatora mnożenia dla tej struktury.
... A następnie przeciąż każdy inny operator aplikacji, który może zostać zastosowany do tych danych.
... A następnie przeciąż wszystkie metody, które mogą wymagać ints.
... I wszystkie te przeciążenia będą musiały nadal zawierać kontrole pod kątem niepoprawnych liczb całkowitych, tak aby można było traktować typ zwracany tej jednej metody tak, jakby zawsze była poprawną liczbą całkowitą w miejscu, w którym ją wywołujesz.
Oryginalna przesłanka jest fałszywa na różne sposoby:
- Jeśli masz niepoprawne wartości, nie możesz uniknąć sprawdzania tych niepoprawnych wartości w dowolnym punkcie kodu, w którym przetwarzasz wartości.
- Jeśli zwracasz coś innego niż int, nie zwracasz int, więc nie możesz traktować tego jak int. Przeciążenie operatora pozwala udawać , ale to tylko udawanie.
- Int z liczbami magicznymi (w tym NULL, NAN, Inf ...) nie jest już tak naprawdę int, jest strukturą biedaka.
- Unikanie wartości null nie uczyni kodu bardziej odpornym, po prostu ukryje problemy z intami lub przeniesie je do złożonej struktury obsługi wyjątków.