Ruby/Powrót do prostych przykładów: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Szymon wro (dyskusja | edycje)
Szymon wro (dyskusja | edycje)
Nie podano opisu zmian
Linia 1:
== Powrót do prostych przykładów ==
 
Rozbierzmy na części kod kilku poprzednich przykładowych programów.
Linia 18:
Ponieważ jest to pierwsze objaśnienie, zbadamy każdą linię osobno.
 
=== Silnie ===
 
<pre>def fact(n)</pre>
 
W pierwszej linii, ''<tt>def''</tt> jest instrukcją służącą do definiowania funkcji (lub, bardziej precyzyjnie, metody; będziemy rozmawiać więcej o tym czym jest metoda w dalszym rozdziale). Tutaj, ''<tt>def''</tt> wskazuje, że funkcja przyjmuje pojedynczy argument, nazwany ''<tt>n''</tt>.
 
<pre>if n == 0</pre>
 
''<tt>if''</tt> służy do sprawdzania warunku. Kiedy warunek jest spełniony, następny fragment kodu jest obliczany; kiedy nie jest, obliczane jest cokolwiek co występuje za ''<tt>else''</tt>.
 
<pre>1</pre>
 
Wartość ''<tt>if''</tt> wynosi <tt>1</tt> jeżeli warunek jest spełniony.
 
<pre>else</pre>
 
Jeżeli warunek nie jest spełniony, obliczany jest kod znajdujący się od tego miejsca do ''<tt>end''</tt>.
 
<pre>n * fact(n-1)</pre>
 
Jeżeli warunek nie jest spełniony, wartość wyrażenia ''<tt>if''</tt> wynosi ''<tt>n''</tt> razy ''<tt>fact(n-1)''</tt>.
 
<pre>end</pre>
 
Pierwszy ''<tt>end''</tt> zamyka instrukcję ''<tt>if''</tt>.
 
<pre>end</pre>
 
Drugi ''<tt>end''</tt> zamyka instrukcję ''<tt>def''</tt>.
 
<pre>puts fact(ARGV[0].to_i)</pre>
 
Ta linia wywołuje naszą funkcję ''<tt>fact()''</tt> używając wartości z linii poleceń oraz wypisuje wynik.
 
''<tt>ARGV''</tt> jest tablicą, która zawiera argumenty z linii poleceń. Elementy ''<tt>ARGV''</tt> są łańcuchami znakowymi, więc aby dokonać konwersji na liczby całkowite używamy metody ''<tt>to_i''</tt>. Ruby nie zamienia łańcuchów na liczby automatycznie tak jak Perl.
 
Co się stanie jeśli podamy naszemu programowi liczbę ujemną? Widzisz problem? Umiesz go rozwiązać?
 
=== Łańcuchy znakowe ===
 
Teraz zbadamy nasz program - łamigłówkę z rozdziału o [[Ruby/Łańcuchy znakowe|łańcuchach znakowych]]. Ponieważ jest on nieco długi, ponumerujmy linie by móc się łatwo do nich odwoływać.
Linia 78:
</pre>
 
W tym programie jest użyta nowa struktura sterująca - ''<tt>while''</tt>. Kod pomiędzy ''<tt>while''</tt> jej kończącym ''<tt>end''</tt> będzie wykonywany w pętli tak długo jak pewien określony warunek pozostanie prawdziwy. W tym przypadku ''<tt>guess=STDIN.gets''</tt> jest zarówno aktywną instrukcją (pobierającą linię wejściową od użytkownika i zachowującą ją jako ''<tt>guess''</tt>), oraz warunkiem (jeżeli nie ma żadnego wejścia, ''<tt>guess''</tt>, które reprezentuje wartość całego wyrażenia ''<tt>guess=STDIN.gets expression''</tt>, będzie miało wartość ''<tt>nil''</tt>, która spowoduje przerwanie pętli ''<tt>while''</tt>).
 
''<tt>STDIN''</tt> oznacza obiekt standardowego wejścia. Zwykle, ''<tt>guess=gets''</tt> robi to samo co ''<tt>guess=STDIN.gets''</tt>.
 
''<tt>rand(3)''</tt> w linii 2 zwraca losową liczbę w przedziale od 0 do 2. Ta losowa liczba jest użyta do wyciągnięcia jednego elementu z tablicy ''<tt>words''</tt>.
 
W linii 5 czytamy jedną linię ze standardowego wejścia przez metodę ''<tt>STDIN.gets''</tt>. Jeżeli wystąpi ''EOF'' (end of file - koniec pliku) podczas pobierania linii, ''<tt>gets''</tt> zwróci ''<tt>nil''</tt>. Tak więc kod skojarzony z tą pętlą ''<tt>while''</tt> będzie powtarzany dopóki nie zobaczy ^D (lub ^Z czy też F6 pod DOS/Windows), co oznacza koniec wejścia (wprowadzania).
 
''<tt>guess.chop!''</tt> w linii 6 usuwa ostatni znak z ''<tt>guess''</tt>; w tym wypadku zawsze będzie to znak nowej linii, ''<tt>gets''</tt> dodaje ten znak by odzwierciedlić naciśnięcie przez użytkownika klawisza Enter (Return), ale w naszym przypadku nie jest to potrzebne.
 
W linii 15 drukujemy tajne słowo (''<tt>secret''</tt>). Zapisaliśmy to jako wyrażenie ''<tt>puts''</tt> (ang. "put string" - wrzuć łańcuch) z dwoma argumentami, które są drukowane jeden po drugim; ale można to zapisać równoważnie z jednym argumentem, zapisując ''<tt>secret''</tt> jako ''<tt>#{secret}''</tt> by było jasne, że jest to zmienna która musi być przetworzona, a nie literalne słowo do wydrukowania:
 
<pre>puts "the word is #{secret}."</pre>
 
Wielu programistów uważa, że utworzenie on pojedynczego łańcucha jako argumentu metody ''<tt>puts''</tt> to czytelniejszy sposób formułowania wyjścia.
 
Również my od teraz stosujemy pomysł z używaniem ''<tt>puts''</tt> do standardowego wyjścia naszego skryptu, ale ten skrypt używa również ''<tt>print''</tt> zamiast ''<tt>puts''</tt>, w liniach 4 i 13. ''<tt>puts''</tt> i ''<tt>print''</tt> nie oznaczają dokładnie tego samego. ''<tt>print''</tt> wyświetla dokładnie to, co jest podane; ''<tt>puts''</tt> ponadto zapewnia, że linia na wyjściu posiada znak końca linii. Używanie ''<tt>print''</tt> w liniach 4 i 13 ustawia kursor dalej, poza uprzednio wydrukowanym tekstem zamiast przenosić go na początek następnego wiersza. Tworzy to rozpoznawalny znak zachęty do wprowadzania danych przez użytkownika.
 
W ogóle, cztery wywołania wyjścia poniżej są równoważne:
Linia 112:
</pre>
 
Jeden słaby punkt: czasami okno tekstowe z powodu prędkości działania posiada buforowane wyjście. Poszczególne znaki są buforowane i wyświetlane dopiero gdy pojawi się znak przejścia do nowej linii. Więc, jeżeli skrypt naszej zgadywanki nie pokazuje zachęty dla użytkownika dopóki użytkownik nie poda odpowiedzi, niemal na pewno winne jest buforowanie. Aby upewnić się, że tak się nie stanie możesz wyświetlić (ang. ''flush'' - dosł. "wylać") wyjście jak tylko zostanie wydrukowana zachęta dla użytkownika. ''<tt>flush''</tt> mówi standardowemu urządzeniu wyjściowemu (obiekt nazwany ''<tt>STDOUT''</tt>), "nie czekaj; wyświetl to co masz w tej chwili."
 
<pre>
Linia 142:
</pre>
 
W linii 6 w warunku dla pętli ''<tt>while''</tt> zakodowana jest "na sztywno" wartość ''<tt>true''</tt>, co w efekcie daje nam nieskończoną pętlę. Aby więc przerwać wykonywanie pętli umieściliśmy instrukcje ''<tt>break''</tt> w liniach 8 i 10. Te dwie instrukcje są również przykładem "modyfikatorów ''<tt>if''</tt>". ''Modyfikator if'' wykonuje wyrażenie po swojej lewej stronie wtedy i tylko wtedy, gdy określony warunek jest prawdziwy. Konstrukcja ta jest niezwykła, gdyż działa logicznie od prawej do lewej strony, ale jest dostępna, ponieważ wielu ludziom przypomina ona podobne wzorce obecne w mowie potocznej. Dodatkowo jest ona zwięzła - nie potrzebuje wyrażenia ''<tt>end''</tt> by wskazać interpretatorowi ile kodu następującego po ''<tt>if''</tt> ma być traktowane jako warunek. ''Modyfikator if'' jest wygodnym sposobem używanym w sytuacjach, gdzie wyrażenie i warunek są wystarczająco krótkie by zmieścić się razem w jednej linii skryptu.
 
Rozważ zmiany w interfejsie użytkownika w stosunku do poprzedniego skryptu-zgadywankiłamigłówki. Bieżący interfejs pozwala użytkownikowi zakończyć program poprzez wciśnięcie klawisza Enter (Return) przy pustej linii. Sprawdzamy czy każda linia z wejścia jest pustym łańcuchem, a nie czy nie istnieje.
 
W liniach 7 i 9 mamy "nie-destruktywny" ''<tt>chop''</tt>; znów, pozbywamy się niechcianego znaku końca linii, który zawsze otrzymujemy od ''<tt>gets''</tt>. Dodajmy wykrzyknik i będziemy mieli "destruktywny" ''<tt>chop''</tt>. Jaka to różnica? W Rubim istnieje konwencja dołączania znaków '!' lub '?' do końca nazw pewnych metod. Wykrzyknik (!, czasami wymawiany jako "bang!") oznacza coś potencjalnie destruktywnego, można powiedzieć, coś co może zmienić wartość przylegającego wyrażenia. ''<tt>chop!''</tt> zmienia łańcuch bezpośrednio, ale ''<tt>chop''</tt> daje ci obciętą kopie bez psucia oryginału. Oto ilustracja tej różnicy.
 
<pre>
Linia 159:
</pre>
 
Czasem będziesz też widział w użyciu ''<tt>chomp''</tt> i ''<tt>chomp!''</tt>. Te dwa są bardziej selektywne: końcówka łańcucha jest obcinana tylko wtedy, gdy jest znakiem końca linii. Dla przykładu, ''<tt>"XYZ".chomp!''</tt> nie robi nic. Jeżeli potrzebujesz jakiegoś triku by zapamiętać różnice, pomyśl o osobie lub zwierzęciu, które smakuje coś nim zdecyduje się to ugryźć (ang. ''chomp'' - "jeść niechlujnie"), a toporze rąbiącym jak popadnie (ang. ''chop'' - odrąbanie).
 
Pozostałe konwencje nazywania metod pojawiają się w liniach 8 i 10. Znak zapytania (?, czasem wymawiany w angielskim jako "huh?") oznacza metodę - "predykat" (orzekającą o czymś), która zwraca albo prawdę (''<tt>true''</tt>) albo fałsz (''<tt>false''</tt>).
 
Linia 11 tworzy obiekt będący wyrażeniem regularnym z łańcucha podanego przez użytkownika. Cała właściwa praca wykonywana jest wreszcie w linii 12, która używa ''<tt>gsub''</tt> do globalnego podstawienia każdego spasowania naszego wyrażenia z samym sobą, ale otoczonego przez znaczniki ansiANSI; również ta sama linia wyświetla wyniki.
 
Mogli byśmy podzielić linię 12 na osobne linie, tak jak tutaj:
Linia 179:
</pre>
 
Spójrz ponownie na ostatnią część linii 12. ''<tt>st''</tt> i ''<tt>en''</tt> były zdefiniowane w liniach 1-2 jako sekwencje ANSI które odpowiednio zmieniają i przywracają kolor tekstu. W linii 12 są one zawarte w ''<tt>#{}''</tt> by zostały w ten sposób właściwie zinterpretowane (i nie zobaczymy zamiast nich nazw zmiennych). Pomiędzy nimi widzimy ''<tt>\\&''</tt>. Jest to trochę podstępne. Ponieważ podstawiany łańcuch zawarty jest w cudzysłowach (podwójnych), para odwróconych ukośników będzie zinterpretowana jako jeden ukośnik; co ''<tt>gsub''</tt> zobaczy właściwie jako ''<tt>\&''</tt>, i co spowoduje powstanie specjalnego kodu, który z kolei odwoła się do czegokolwiek, co jako pierwsze będzie pasować do wzorca. Tak więc nowy łańcuch, gdy będzie wyświetlony będzie wyglądał tak jak pierwszy z wyjątkiem tego, że te fragmenty które pasują do wzorca będą wyświetlone w odwróconych kolorach.
<noinclude>
{{ProstaNawigacja|spis=Ruby|poprzart=Ruby/Tablice|poprz=Tablice|nastart=Ruby/Struktury sterujące|nast=Struktury sterujące}}