Prawdopodobnie znasz następujący skrót języka Ruby ( a
jest to tablica):
a.map(&:method)
Na przykład spróbuj wykonać następujące czynności w irb:
>> a=[:a, 'a', 1, 1.0]
=> [:a, "a", 1, 1.0]
>> a.map(&:class)
=> [Symbol, String, Fixnum, Float]
Składnia a.map(&:class)
jest skrótem dla a.map {|x| x.class}
.
Przeczytaj więcej o tej składni w " Co oznacza map (&: name) w Rubim? ".
Poprzez składnię &:class
wywołujesz metodę class
dla każdego elementu tablicy.
Moje pytanie brzmi: czy możesz podać argumenty do wywołania metody? A jeśli tak, to w jaki sposób?
Na przykład, jak przekonwertować następującą składnię
a = [1,3,5,7,9]
a.map {|x| x + 2}
do &:
składni?
Nie sugeruję, że &:
składnia jest lepsza. Interesuje mnie tylko mechanika używania &:
składni z argumentami.
Zakładam, że wiesz, że +
jest to metoda na klasie Integer. W irb możesz spróbować następujących rzeczy:
>> a=1
=> 1
>> a+(1)
=> 2
>> a.send(:+, 1)
=> 2
Symbol#with
może nie istnieć w podstawowej bibliotece, a zdefiniowanie tej metody jest mniej destrukcyjne niż przedefiniowanie istniejącej metody, wciąż zmienia (tj. Nadpisuje) implementację podstawowej klasy biblioteki ruby. Praktykę należy wykonywać bardzo oszczędnie iz dużą ostrożnością. \ n \ n Rozważ dziedziczenie z istniejącej klasy i zmodyfikowanie nowo utworzonej klasy. Generalnie daje to porównywalne wyniki bez negatywnych skutków ubocznych zmiany klas podstawowych rubinów.Symbol
klasy - nie jest to trywialne (jeśli w ogóle możliwe), ponieważ jest to taka klasa podstawowa (new
na przykład nie ma metody), a jej użycie będzie uciążliwe (jeśli w ogóle możliwe), co pokona cel ulepszenia ... jeśli możesz pokazać implementację, która to wykorzystuje i osiąga porównywalne wyniki - udostępnij!with
metodę, zdefiniujcall
. Następnie możesz zrobić takie rzeczy, jaka.map(&:+.(2))
odkądobject.()
używa#call
metody. A kiedy już to robisz, możesz pisać zabawne rzeczy, takie jak:+.(2).(3) #=> 5
- czujesz się trochę LISPY, nie?Na przykład można zrobić
a.map(&2.method(:+))
.Oto jak to działa: -
2.method(:+)
dajeMethod
przedmiot. Następnie&
,2.method(:+)
faktycznie#to_proc
metoda wywołania , która czyni jąProc
obiektem. Następnie wykonaj Jak nazywasz operator &: w Rubim? .źródło
Pry
powyższe dane wyjściowe, możesz je uzyskać, jak to działa.+
jest przemienny.Jak potwierdza post, do którego utworzyłeś link,
a.map(&:class)
nie jest skrótem dla,a.map {|x| x.class}
ale dlaa.map(&:class.to_proc)
.Oznacza to, że
to_proc
wywoływane jest wszystko, co następuje po&
operatorze.Więc możesz
Proc
zamiast tego podać bezpośrednio :Wiem, że najprawdopodobniej jest to sprzeczne z celem twojego pytania, ale nie widzę innego wyjścia - nie chodzi o to, że określasz, która metoda ma zostać wywołana, po prostu przekazujesz jej coś, na co odpowiada
to_proc
.źródło
my_proc = Proc.new{|i| i + 1}
,[1,2,3,4].map(&my_proc) => [2,3,4,5]
Krótka odpowiedź: nie.
Podążając za odpowiedzią @ rkon, możesz również zrobić to:
źródło
&->(_){_ + 2}
jest krótszy niż{|x| x + 2}
.Istnieje inna natywna opcja dla wyliczeń, która moim zdaniem jest ładna tylko z dwóch argumentów. klasa
Enumerable
ma metodę,with_object
która następnie zwraca innąEnumerable
.Możesz więc wywołać
&
operator dla metody z każdym elementem i obiektem jako argumentami.Przykład:
W przypadku, gdy chcesz więcej argumentów, powinieneś powtórzyć proces, ale moim zdaniem jest brzydki:
źródło
Zamiast samodzielnie łatać klasy podstawowe, jak w przyjętej odpowiedzi, korzystanie z funkcjonalności klejnotu Facets jest krótsze i czystsze :
źródło
Nie jestem pewien co do
Symbol#with
już opublikowanego, trochę uprościłem i działa dobrze:(używa również
public_send
zamiast,send
aby zapobiec wywoływaniu metod prywatnych, równieżcaller
jest już używane przez Ruby, więc było to mylące)źródło