2013-02-14 16 views
31

Sto imparando rotaie e seguenti this thread. Sono bloccato con il metodo to_proc. Considero i simboli solo come alternative alle stringhe (sono come gli archi ma meno costosi in termini di memoria). Se c'è qualcos'altro che mi manca per i simboli, quindi per favore dimmelo. Si prega di spiegare in modo semplice che cosa significa to_proc e a cosa serve.Cosa significa to_proc method?

risposta

77

Alcuni metodi prendono un blocco, e questo modello appare frequentemente per un blocco:

{|x| x.foo} 

e la gente vorrebbe scrivere che in un modo più conciso. Per fare questo, un simbolo, il metodo Symbol#to_proc, fusione di classe implicita, e & operatore vengono utilizzati in combinazione. Se si mette & davanti a un'istanza Proc nella posizione di discussione, che viene interpretato come un blocco. Se si combinano qualcosa di diverso da un'istanza Proc con &, quindi classe implicita fusione cercherà di convertire tale a un'istanza Proc utilizzando to_proc metodo definito su tale oggetto se non v'è alcuna. In caso di un'istanza Symbol, to_proc opere in questo modo:

:foo.to_proC# => ->x{x.foo} 

Ad esempio, si supponga che si scrive in questo modo:

bar(&:foo) 

L'operatore & è combinato con :foo, che non è un'istanza Proc , in modo da getto classe implicita applica Symbol#to_proc ad esso, che dà ->x{x.foo}. Il & ora si applica al presente e viene interpretato come un blocco, che dà:

bar{|x| x.foo} 
+3

grazie per la spiegazione +1 :) – swapnesh

+0

Inoltre, in base a questo , è 20 tempi più veloci durante il runtime. –

+0

Comprendo che '& proc' fornisce un blocco,' 'x 'risulta in x diventando proc allora l'intera cosa dà anche un blocco. Capisco anche che Symbol ha il metodo to_proc. Tuttavia la parte che non capisco e ritengo che questa risposta manchi, è come i simboli e i metodi sono collegati. Voglio dire, non è che tutti i metodi siano disponibili anche con i nomi dei simboli –

39

Il modo più semplice per spiegare questo è con alcuni esempi.

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

è lo stesso:

(1..3).collect {|num| num.to_s} #=> ["1", "2", "3"] 

e

[1,2,3].collect(&:succ) #=> [2, 3, 4] 

è lo stesso:

[1,2,3].collect {|num| num.succ} #=> [2, 3, 4] 

to_proc restituisce un oggetto Proc che risponde al metodo specificato per simbolo. Quindi nel terzo caso, l'array [1,2,3] chiama il suo metodo collect e. succ è il metodo definito dalla classe Array. Quindi questo parametro è un modo breve per dire di raccogliere ogni elemento nell'array e restituire il suo successore e da questo creare un nuovo array che risulta in [2,3,4]. Il simbolo: succ viene convertito in un oggetto Proc in modo da chiamare il metodo succ di Array.

+3

@Dilon +1 per gli esempi :) – swapnesh

7

Per me la spiegazione più chiara è vedere una semplice implementazione di esso.Ecco quello che potrebbe apparire come se fossi reimplementare Simbolo # to_proc:

class Symbol # reopen Symbol class to reimplement to_proc method 
    def to_proc 
    ->(object) { object.send(self) } 
    end 
end 

my_lambda = :to_s.to_proc 

puts my_lambda.(1) # prints '1'; .() does the same thing as .call() 
puts my_lambda.(1).class # prints 'String' 

puts [4,5,6].map(&:to_s) # prints "4\n5\n6\n" 
puts [4,5,6].map(&:to_s).first.class # prints 'String' 
+1

Questo! A proposito, non dovrebbe essere 'my_to_proc' sul metodo che stai provando a scovare la patch sulla classe' Symbol'? –

+0

@AgungSetiawan Buona cattura! Invece, ho rinominato la chiamata in modo che chiamasse to_proc invece di my_to_proc. –

1

Per chiunque ancora un po 'perplesso, eseguendo il seguente codice potrebbe rendere le cose un po' più chiaro:

class Symbol 
    def to_proc 
    proc do |obj| 
     puts "Symbol proc: #{obj}.send(:#{self})" 
     obj.send(self) 
    end 
    end 
end 

class Array 
    def map(&block) 
    copy = self.class.new 
    self.each do |index| 
     puts "Array.map: copy << block.call(#{index})" 
     copy << block.call(index) 
    end 
    copy 
    end 
end 

remapped_array = [0, 1, 2].map &:to_s 
puts "remapped array: #{remapped_array.inspect}" 

Questi non la sono implementazioni effettive di Symbol.to_proc o Array.map, sono solo versioni semplificate che sto usando per dimostrare come funzionano le chiamate map &:to_s e simili.