Większość zdaje sobie sprawę ze _
specjalnego znaczenia IRB jako posiadacza ostatniej zwracanej wartości, ale nie o to tutaj pytam.
Zamiast tego pytam, _
kiedy jest używany jako nazwa zmiennej w zwykłym starym-Ruby-kodzie. Tutaj wydaje się, że zachowuje się w specjalny sposób, podobnie jak zmienna „nie przejmuj się” (à la Prolog ). Oto kilka przydatnych przykładów ilustrujących jego wyjątkowe zachowanie:
lambda { |x, x| 42 } # SyntaxError: duplicated argument name
lambda { |_, _| 42 }.call(4, 2) # => 42
lambda { |_, _| 42 }.call(_, _) # NameError: undefined local variable or method `_'
lambda { |_| _ + 1 }.call(42) # => 43
lambda { |_, _| _ }.call(4, 2) # 1.8.7: => 2
# 1.9.3: => 4
_ = 42
_ * 100 # => 4200
_, _ = 4, 2; _ # => 2
Były one uruchamiane bezpośrednio w Rubim (z puts
dodanymi s) - nie w IRB - aby uniknąć konfliktu z jego dodatkową funkcjonalnością.
To wszystko jest jednak wynikiem moich własnych eksperymentów, ponieważ nie mogę nigdzie znaleźć żadnej dokumentacji na temat tego zachowania (co prawda nie jest to najłatwiejsza rzecz do wyszukania). Ostatecznie jestem ciekawy, jak to wszystko działa wewnętrznie, więc mogę lepiej zrozumieć, co jest specjalnego _
. Dlatego proszę o odniesienia do dokumentacji i, najlepiej, kodu źródłowego Rubiego (i być może RubySpec ), które pokazują, jak _
zachowuje się w Rubim.
Uwaga: większość z tego wynikła z dyskusji z @Niklas B.
lambda { |_, _| _ }.call(4, 2)
między 1,8 a 1,9 to tylko niezamierzony efekt uboczny? Podobnie jak w „normalnych” okolicznościach, w których nazwy zmiennej nie można powielić, kolejność, w jakiej są przypisywane, jest nieistotna.|_,_,...|
wyeliminowanie błędu duplikatu._
jest prawidłowym identyfikatorem. Identyfikatory nie mogą zawierać tylko podkreślenia, mogą również być podkreśleniem._ = o = Object.new _.object_id == o.object_id # => true
Możesz go również użyć jako nazw metod:
def o._; :_ end o._ # => :_
Oczywiście nie jest to dokładnie czytelna nazwa, ani nie przekazuje czytelnikowi żadnych informacji o tym, do czego odwołuje się zmienna ani do czego służy metoda.
IRB
w szczególności ustawia_
wartość ostatniego wyrażenia:$ irb > 'asd' # => "asd" > _ # => "asd"
Tak jak w kodzie źródłowym , po prostu ustawia
_
ostatnią wartość:@workspace.evaluate self, "_ = IRB.CurrentContext.last_value"
Przeszukałem trochę repozytorium. Oto co znalazłem:
W ostatnich wierszach pliku
id.c
jest wywołanie:REGISTER_SYMID(idUScore, "_");
grep
Znalezienie źródła dlaidUScore
dało mi dwa pozornie istotne wyniki:shadowing_lvar_gen
funkcjiwarn_unused_var
funkcjishadowing_lvar_gen
wydaje się być mechanizmem, za pomocą którego formalny parametr bloku zastępuje zmienną o tej samej nazwie, która istnieje w innym zakresie. Jest to funkcja, która wydaje się zgłaszać „zduplikowaną nazwę argumentu”SyntaxError
ostrzeżenie o i „cieniowaniu zewnętrznej zmiennej lokalnej”.Po znalezieniu
grep
źródła dlashadowing_lvar_gen
, w dzienniku zmian dla Rubiego 1.9.3 znalazłem następujące informacje :Co może być źródłem tej linii :
if (idUScore == name) return name;
Z tego wnioskuję, że w takiej sytuacji
proc { |_, _| :x }.call :a, :b
jedna_
zmienna po prostu przesłania drugą.Oto omawiany commit . Zasadniczo wprowadził te dwie linie:
if (!uscore) uscore = rb_intern("_"); if (uscore == name) return;
Od chwili, gdy
idUScore
nawet nie istnieje, widocznie.źródło
lambda { |_, _| 42 }
robót natomiastlambda { |x, x| 42 }
nie.|_, _|
działa, ale|__, __|
nie._
wydaje się mieć jakieś specjalne znaczenie, zobaczę, czy uda mi się wydobyć jakiekolwiek informacje ze źródła Rubiego.