/ / Zrozumienie `array.map (&: method)` [duplicate] - ruby, symbol

Zrozumienie `array.map (&: method)` [duplicate] - ruby, symbol

Dlaczego:

[1,2,3,4,5].map(&:to_s) #=> ["1", "2", "3", "4", "5"]

pracować, ale:

[1,2,3,4,5].map(&:*(2))

zgłasza nieoczekiwany błąd składni?

Odpowiedzi:

3 dla odpowiedzi № 1

& nazywa się to_proc operator. To wywołuje to_proc metoda na wyrażeniu następującym po nim, a następnie przekazuje wynikowy proces do metody jako blok.

W przypadku &:to_s, :to_s jest symbolem, więc operator dzwoni Symbol#to_proc. Dokumenty są trochę zniekształcone, ale wystarczy powiedzieć, że te dwa wyrażenia są mniej więcej równoważne:

my_proc = :to_s.to_proc
my_proc = Proc.new {|obj| obj.to_s }

Tak więc odpowiedź na pytanie "Dlaczego nie" &:*(2) praca? "to wyrażenie następujące po & operator, :*(2), nie jest prawidłowym wyrażeniem Ruby, a dla parsera Ruby jest tak samo sensowne jak "hello"(2).

Jest przy okazji sposób, aby zrobić to, co próbujesz zrobić:

[1,2,3,4,5].map(&2.method(:*))
# => [2, 4, 6, 8, 10]

W powyższym kodzie 2.method(:*) zwraca odniesienie do * metoda obiektu 2 jak metoda obiekt. Obiekty metod zachowują się podobnie do obiektów Proc i odpowiadają na nie to_proc. Jednak powyższe nie jest dokładnie równoważne - tak jest 2 * n zamiast n * 2 (rozróżnienie, które nie ma znaczenia, jeśli n jest również numerycznym) i nie jest bardziej zwięzły ani czytelny niż {|n| n * 2 }i tak rzadko warte są kłopotów.


-1 dla odpowiedzi № 2

Ampersand and object (&: method)

Operator & można również użyć do przekazania obiektu jako bloku do metody, jak w poniższym przykładzie:

arr = [ 1, 2, 3, 4, 5 ]

arr.map { |n| n.to_s }
arr.map &:to_s

Oba powyższe przykłady mają taki sam wynik. W obu metoda map przyjmuje tablicę arr i blok, a następnie uruchamia blok na każdym elemencie tablicy. Kod wewnątrz bloku uruchamia to_s na każdym elemencie, przekształcając go z liczb całkowitych na ciągi. Następnie metoda map zwraca nową tablicę zawierającą przekonwertowane elementy.

Pierwszy przykład jest powszechny i ​​szeroko stosowany. Drugi przykład może na pierwszy rzut oka wyglądać nieco tajemniczo. Zobaczmy, co się dzieje:

W Ruby pozycje poprzedzone dwukropkiem (:) są symbolami. Jeśli nie znasz klasy / typu danych Symbol, proponuję Ci go przeczytać i przeczytać kilka artykułów, zanim przejdziesz dalej. Wszystkie nazwy metod w Ruby są przechowywane wewnętrznie jako symbole. Poprzez prefiksowanie nazwy metody dwukropkiem, nie przekształcamy metody w symbol, ani nie wywołujemy metody, tylko przekazujemy nazwę metody (odwołując się do metody). W powyższym przykładzie przechodzimy: to_s, który jest odniesieniem do metody to_s, do operatora ampersand (&), który utworzy proc (przez wywołanie to_proc pod maską). Proc bierze wartość jako argument, wywołuje to_s na nim i zwraca wartość przekonwertowaną na ciąg znaków.

Chociaż :Symbol to_s jest zawsze taki sam, podczas uruchamiania pętli map będzie odwoływał się do metody to_s klasy odpowiadającej każdemu elementowi tablicy. Jeśli przekażemy tablicę taką jak [21, 4.453,: foobar,] do metody map, to metoda to_s klasy Fixnum zostanie zastosowana (wywołana) na pierwszym elemencie, metoda to_s klasy Float zostanie zastosowana do drugi element i metoda to_s klasy Symbol zostaną zastosowane do trzeciego elementu. Ma to sens, ponieważ nie przekazujemy rzeczywistej metody to_s operatorowi ampersand, tylko jej nazwie.

Poniżej znajduje się przykład tworzenia procesu, który pobiera argument, wywołuje na nim metodę i zwraca wynik tej metody.

p = :upcase.to_proc
p.call("foo bar")
Output:
=> "FOO BAR"

Zobaczmy, co się dzieje w arr.map &: to_s

  1. Przy każdej iteracji mapy jeden element tablicy (liczba całkowita) jest przekazywany do &: to_s
  2. The:symbol to_s (który jest odniesieniem do metody to_s) jest przekazywany do operatora &, który tworzy proc, który pobiera argument (element tablicy), wywołuje to_s na argumencie i zwraca wartość przekonwertowaną na łańcuch;
  3. Metoda map zwraca nową tablicę zawierającą ciągi "1", "2", "3", "4" i "5".