2012-09-27 18 views

Odpowiedz

13

Dzieje się tak z powodu działania parsera Ruby. Zmienne są definiowane przez analizator składni, który przechodzi przez kod wiersz po wierszu, niezależnie od tego, czy zostanie faktycznie wykonany.

Gdy analizator składni widzi x =, definiuje lokalną zmienną x (z wartością nil) odtąd w bieżącym zakresie. Od if/unless/case/for/while nie tworzy się nowego zakresu, x jest zdefiniowany i dostępny poza blokiem kodu. A ponieważ blok wewnętrzny nigdy nie jest oceniany, ponieważ warunkowy jest fałszywy, x nie jest przypisany do (i dlatego jest nil).

Oto podobny przykład:

defined?(x) and x = 0 
x #=> nil 

Należy pamiętać, że jest to raczej opis wysokim poziomie, co się dzieje, i niekoniecznie jest dokładnie jak działa parser.

+0

Ah, pobili mnie do tego. Ładne wyjaśnienie. – nneonneo

2

Jest to związane z dziwactwem zasad klasyfikacji Rubiego.

W ruby, nieodkryta zmienna x pojawiająca się sama może być zmienną lokalną lub wywołaniem metody - gramatyka nie może powiedzieć, która. Od parsera zależy to, czy rozwiązuje lokalne odwołania do zmiennych. Zasada jest prosta: jeśli przypisanie do zmiennej o tej samej nazwie było już widziane w zasięgu lokalnym, to referencja jest zmienną lokalną, a odniesienie jest powiązane z tą zmienną lokalną. W przeciwnym razie jest to wywołanie metody, które zostanie sprawdzone jako takie w czasie wykonywania.

Lokalne referencje zmiennych w języku Ruby są optymalizowane do wyszukiwania tablic (każdej zmiennej lokalnej przypisuje się "gniazdo", a powiązane odwołania do zmiennych lokalnych generowane przez analizator składni są konwertowane na odniesienia do szczelin). Tablica jest inicjowana ze wszystkimi nil:

/* initialize local variables */ 
for (i=0; i < local_size; i++) { 
    *sp++ = Qnil; 
} 

Tak więc, jeśli odwołać się do zmiennej lokalnej, który nie został przypisany przez oprawionego lokalnego odniesienia (co może się zdarzyć, jeśli tylko nie było pomijane przypisanie powyżej odniesienia w tym samym zasięgu lokalnym), otrzymujesz nil.

1

Myślałem Twoje pytanie było ciekawe, więc starałem się szukać go i znalazłem to: I don't understand ruby local scope

Prawidłowa odpowiedź wydaje się być wprowadzone Jorg.

Spójrzmy na to, co dzieje się podczas próby uzyskania dostępu do zmiennej, która nie jest zainicjowany:

NameError: undefined local variable or method `UNDECLAREDVAR' for main:Object 

Wyjątkiem stwierdza, że ​​jest niedostępna, aby ocenić, czy zmiennej lub metody. Powodem, dla którego nie wyrzuca tego samego wyjątku, jest to, że niezainicjowane zmienne lokalne są ustawione na zero. Tak więc puts x jest w porządku, ponieważ interpretator wie, że x jest zmienna, ale niezainicjowana, a nie jest metodą.

Powiązane problemy