2016-01-07 10 views
6

wywołuje metodę można zwykle pominąć odbiornik i nawiasy dla argumentów:Dlaczego wywołanie metody musi zostać ujednoznacznione, skoro może w zasadzie być stałą?

def foo; "foo" end 
foo # => "foo" 

W powyższym przypadku, foo jest niejednoznaczna między wywołania metody oraz odniesienie do potencjalnego zmiennej lokalnej. W przypadku braku tej ostatniej jest interpretowany jako wywołanie metody.

Jednak, gdy nazwa metody może w zasadzie być nazwą stałą (tj. Gdy zaczyna się od dużej litery i składa się tylko z liter), wydaje się, że potrzebna jest ujednoznacznienie.

def Foo; "Foo" end 
Foo # => NameError: uninitialized constant Foo 
Foo() # => "Foo" 
self.Foo # => "Foo" 

Dlaczego tak się dzieje? Dlaczego wywołanie metody musi być jawnie odróżnione od odwołania do stałej nawet pod nieobecność stałej o tej samej nazwie?

Odpowiedz

5

Zestaw zmiennych lokalnych, które jest w zakresie w danym punkcie programu ustala lexically, a zatem może być określany statycznie, tak jak już analizy składni. Tak więc Ruby wie jeszcze przed uruchomieniem, które zmienne lokalne są w zasięgu i może w ten sposób odróżnić wysyłanie wiadomości od lokalnej dereferencji zmiennej.

Stałe są najpierw wyszukiwane leksykalnie, ale potem przez dziedziczenie, tj. Dynamicznie. Nie wiadomo, które stałe są w zasięgu przed uruchomieniem. Dlatego, aby ujednoznacznić, Ruby zawsze zakłada, że ​​jest stała, chyba że nie jest to oczywiste, tj. Wymaga argumentów lub ma odbiornik lub oba.

+0

Dzięki za odpowiedź. – sawa

+1

Fakt, że zmienne lokalne są zdefiniowane w czasie parowania, jest przyczyną nieco nieintuicyjnego zachowania 'if false then foo = 43 end; foo # => zero (zamiast NameError) '. –

+0

@ JörgWMittag To ma sens. –

0

Zadajesz świetne pytanie. Jak zauważysz, ruby ​​chce traktować to jako stałą i dlatego stale sprawdzać.

Poniższy fragment pokazuje jednak bieżące zachowanie, a następnie modyfikując const_missing, wydaje się, że uzyskuje pożądane zachowanie. I prawdę mówiąc, nie mogę niczego złamać.

Mój wniosek jest taki, że ktoś już zasugerował, po prostu decyzja projektowa, ale jest dziwna, ponieważ w ogóle rubin faworyzuje konwencję a egzekwowanie.

Albo brakuje mi jakiegoś przypadku, w którym rzeczy się mylą i dzieje się coś złego.

<script type="text/ruby"> 
 
def puts(s); Element['#output'].html = Element['#output'].html + s.to_s.gsub("\n", "<br/>").gsub(" ", "&nbsp;") + "<br/>"; end 
 

 
class ImAClass 
 
    def self.to_s 
 
    "I am ImAClass Class" 
 
    end 
 
end 
 

 
def ImAMethod 
 
    "hello" 
 
end 
 

 
class DontKnowWhatIAm 
 
    def self.to_s 
 
    "a Class" 
 
    end 
 
end 
 

 
def DontKnowWhatIAm 
 
    "a method" 
 
end 
 

 
puts "ImAClass: #{ImAClass}" 
 

 
begin 
 
    puts "ImAMethod: #{ImAMethod}" 
 
rescue Exception => e 
 
    puts "confusion! #{e.message}" 
 
end 
 

 
puts "ImAMethod(): #{ImAMethod()}" 
 

 
puts "DontKnowWhatIAm: #{DontKnowWhatIAm}" 
 

 
puts "DontKnowWhatIAm(): #{DontKnowWhatIAm()}" 
 

 
class Module 
 
    alias_method :old_const_missing, :const_missing 
 
    def const_missing(c) 
 
    if self.respond_to? c 
 
     self.send c 
 
    else 
 
     old_const_missing(c) 
 
    end 
 
    end 
 
end 
 

 
class Foo 
 
    def self.Bar 
 
    "im at the bar" 
 
    end 
 
end 
 

 
puts "now we can just say: Foo::Bar and it works! #{Foo::Bar}" 
 
    
 
</script> 
 

 

 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script> 
 
<div id="output" style="font-family: courier"></div>

2

Nie ma wielkiego powodu za tą różnicą. Chciałem, żeby foo zachowywał się jak foo(), jeśli w tym zakresie nie ma zmiennej lokalnej foo. Pomyślałem, że jest to przydatne do tworzenia DSL itp. Ale nie widziałem powodu, aby Foo zachowywał się jak Foo().

+4

Co za niespodzianka!本 物 の 松本 さ ん で す か. – sawa

Powiązane problemy