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

Usunięta treść Dodana treść
Szymon wro (dyskusja | edycje)
Nie podano opisu zmian
Szymon wro (dyskusja | edycje)
Nie podano opisu zmian
Linia 4:
 
<pre>
ruby> $fooa
nil
ruby> @fooa
nil
ruby> fooa
ERR: (eval):1: undefined local variable or method `fooa' for main(Object)
</pre>
 
Pierwsze przypisanie, które robisz do zmiennej lokalnej odgrywa rolę jakby deklaracji. Jeżeli Odwołaszodwołasz się do niezainicjalizowanej zmiennej lokalnej, interpreter Rubiego nie będzie pewny, czy odwołujesz się do nieprawdziwejprawdziwej zmiennej. Możesz, dla przykładu, zrobić błąd w nazwie metody. Dlatego zobaczyłeś raczej ogólną informację o błędzie.
 
Zazwyczaj zasięgiem zmiennej lokalnej jest jedno z poniższych:
 
* <tt>proc { ... }</tt>
* <tt>loop { ... }</tt>
* <tt>def ... end</tt>
* <tt>class ... end</tt>
Linia 23:
* cały skrypt (chyba że zastosowano jedno z powyższych)
 
W następnynastę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>barb</tt> jest ograniczony lokalnie do pętli. Gdy pętla zostaje przerwana zmienna <tt>barb</tt> jest niezdefiniowanyniezdefiniowana.
 
<pre>
ruby> fooa = 44; puts fooa; defined?(fooa)
44
"local-variable"
ruby> loop {barb=45; puts barb; break}; defined?(barb)
45
nil
</pre>
 
Obiekty procedurowe, które żyją w tym pewnym zakresie widoczności współdzielą tylko zmienne lokalne, które również należą do tego zakresu. Tutaj, zmienna lokalna <tt>bara</tt> jest współdzielona przez <tt>main</tt> oraz obiekty procedurowe <tt>p1</tt> i <tt>p2</tt>:
 
<pre>
ruby> bara = nil
nil
ruby> p1 = proc {|n| bara=n}
#<Proc:0x8deb0>
ruby> p2 = proc {bara}
#<Proc:0x8dce8>
ruby> p1.call(5)
5
ruby> bara
5
ruby> p2.call
Linia 51:
</pre>
 
Zauważ, że "nie można pominąć <tt>bara = nil</tt>" na początku nie może zostać pominięte. To przypisanie zapewnia, że zasięg zmiennej <tt>bara</tt> będzie obejmie <tt>p1</tt> i <tt>p2</tt>. Inaczej <tt>p1</tt> i <tt>p2</tt> postawiłyby byutworzyłyby swoje własne zmienne lokalne <tt>bara</tt>, i rezultatem wywołania <tt>p2</tt> byłby błąd "undefined local variable or method" (niezdefinowana zmienna lokalna lub metoda). Moglibyśmy użyć <tt>bara = 0</tt>, ale użycie <tt>nil</tt> jest pewną uprzejmością wobec tych, którzy będą później czytać nasz kod później. WskazujePokazuje to naprawdę jasno, że tylko ustanawiamy zakres, ponieważ wartość przypisywana do zmiennej nie jest zawiera żadnego dodatkowego znaczenia (<tt>nil</tt>).
 
PotężnąPotężna zaleta obiektów procedurowych wypływa z ich zdolności do bycia przekazywanymi jako argumenty: współdzielone zmienne lokalne pozostają poprawdepoprawne nawet wtedy, gdy przekazane poza pierwotny zakres.
 
<pre>
ruby> def boxpudelko
| contentszawartosc = nil
| getwez = proc {contentszawartosc}
| setwloz = proc {|n| contentszawartosc = n}
| return getwez, setwloz
| end
nil
ruby> readerodczyt, writerzapis = boxpudelko
[#<Proc:0x40170fc0>, #<Proc:0x40170fac>]
ruby> readerodczyt.call
nil
ruby> writerzapis.call(2)
2
ruby> readerodczyt.call
2
</pre>
 
Ruby jest szczególnie sprytny jeśli chodzi o zakres. Ewidentnie widać w naszym przykładzie widać, że zmienna <tt>contentszawartosc</tt> jest współdzielona pomiędzy <tt>readerodczyt</tt> i <tt>writerzapis</tt>. Możemy również wytworzyć wiele par <tt>readerodczyt-writerzapis</tt> używając metody <tt>boxpudelko</tt> zdefiniowanegozdefiniowanej powyżej. Każda para współdzieli zmienną (lokalną!) <tt>contentszawartosc</tt>, aale pary nie kolidują ze sobą nawzajem.
 
<pre>
ruby> reader_1odczyt_1, writer_1zapis_1 = boxpudelko
[#<Proc:0x40172820>, #<Proc:0x4017280c>]
ruby> reader_2odczyt_2, writer_2zapis_2 = boxpudelko
[#<Proc:0x40172668>, #<Proc:0x40172654>]
ruby> writer_1zapis_1.call(99)
99
ruby> reader_1odczyt_1.call
99
ruby> reader_2odczyt_2.call # nothing is in this box yet
nil
</pre>
 
Ten rodzaj programowania mógłbymożna byćby uważanyuważać za lekko perwersyjny zorientowany obiektowo szkielet[[w:Framework|framework]]. Metoda <tt>boxpudelko</tt> odgrywa rolę klasy podczas gdy <tt>getwez</tt> i <tt>setwloz</tt> służą jako metody (z wyjątkiem tego, że tak naprawdę nie są nazwami metod, co mogłoby różnić w każdą instancji <tt>box</tt>) natomiast <tt>contentszawartosc</tt> jest samotną zmienną intancjiinstancji. Oczywiście stosowanie właściwego szkieletu klas Rubiego prowadzi do znacznie bardziej czytelnego kodu.
<noinclude>
{{ProstaNawigacja|spis=Ruby|poprzart=Ruby/Zmienne instancji|poprz=Zmienne instancji|nastart=Ruby/Stałe klasowe|nast=Stałe klasowe}}