Ruby/Zmienne lokalne: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Fservant (dyskusja | edycje)
m Poprawione nazwy zmiennych z przykładu, tak aby zgadzały się z opisem
Nie podano opisu zmian
 
Linia 27:
Użyty w następnym przykładzie <tt>defined?</tt> jest operatorem, który sprawdza czy identyfikator został zdefiniowany. Zwraca on opis identyfikatora, jeśli jest on zdefiniowany lub, w przeciwnym razie, <tt>nil</tt>. Jak widzisz, zasięg zmiennej <tt>b</tt> jest ograniczony lokalnie do pętli. Gdy pętla zostaje przerwana zmienna <tt>b</tt> jest niezdefiniowana.
 
<sourcesyntaxhighlight lang="ruby">
a = 44
puts defined?(a) #=> local-variable
Linia 36:
end
puts defined?(b) #=> nil
</syntaxhighlight>
</source>
 
Obiekty procedurowe, które żyją w pewnym zakresie widoczności współdzielą tylko te zmienne lokalne, które również należą do tego zakresu. Tutaj, zmienna lokalna <tt>a</tt> jest współdzielona przez <tt>main</tt> oraz obiekty procedurowe <tt>l1</tt> i <tt>l2</tt>:
 
<sourcesyntaxhighlight lang="ruby">
a = nil
l1 = lambda {|n| a=n}
Linia 47:
puts a #=> 5
puts l2.call #=> 5
</syntaxhighlight>
</source>
 
Zauważ, że nie można pominąć <tt>a = nil</tt> na początku. To przypisanie zapewnia, że zasięg zmiennej <tt>a</tt> obejmie <tt>l1</tt> i <tt>l2</tt>. Inaczej <tt>l1</tt> i <tt>l2</tt> utworzyłyby swoje własne zmienne lokalne <tt>a</tt>, i rezultatem wywołania <tt>l2</tt> byłby błąd "undefined local variable or method" (niezdefiniowana zmienna lokalna lub metoda). Moglibyśmy użyć <tt>a = 0</tt>, ale użycie <tt>nil</tt> jest pewną uprzejmością wobec przyszłych czytelników naszego kodu. Pokazuje naprawdę jasno, że tylko ustanawiamy zakres, ponieważ wartość przypisana do zmiennej nie niesie żadnego specjalnego znaczenia (<tt>nil</tt>).
Linia 55:
W rozdziale o [[Ruby/Domknięcia i obiekty procedurowe|domknięciach i obiektach procedurowych]] wspomnieliśmy, że domknięcia i obiekty procedurowe zachowują kontekst używanych zmiennych lokalnych. Jest to bardzo potężna zaleta: współdzielone zmienne lokalne pozostają poprawne nawet wtedy, gdy przekazane są poza pierwotny zakres.
 
<sourcesyntaxhighlight lang="ruby">
def pudelko
zawartosc = nil
Linia 68:
zapis.call(2)
puts odczyt.call #=> 2
</syntaxhighlight>
</source>
 
Ruby jest szczególnie sprytny jeśli chodzi o zakres. W naszym przykładzie ewidentnie widać, że zmienna <tt>zawartosc</tt> jest współdzielona pomiędzy <tt>odczyt</tt> i <tt>zapis</tt>. Możemy również wytworzyć wiele par <tt>odczyt-zapis</tt> używając metody <tt>pudelko</tt> zdefiniowanej powyżej. Każda para współdzieli zmienną <tt>zawartosc</tt>, ale pary nie kolidują ze sobą nawzajem. Dopóki istnieją obiekty procedurowe, zachowane są ich konteksty wywołania wraz z odpowiadającymi im zmiennymi lokalnymi!
 
<sourcesyntaxhighlight lang="ruby">
odczyt_1, zapis_1 = pudelko
odczyt_2, zapis_2 = pudelko
Linia 81:
# w tym pudelku jeszcze nic nie ma
puts odczyt_2.call #=> nil
</syntaxhighlight>
</source>
 
Powyższy kod można by wręcz uważać za lekko perwersyjny zorientowany obiektowo [[w:Framework|framework]]. Metoda <tt>pudelko</tt> odgrywa rolę klasy podczas gdy <tt>wez</tt> i <tt>wloz</tt> służą jako metody, natomiast <tt>zawartosc</tt> jest samotną zmienną instancji. Oczywiście stosowanie właściwego szkieletu klas Rubiego prowadzi do znacznie bardziej czytelnego kodu ;).