Ruby Block, Procs e Instance_eval
-
28-10-2019 - |
Domanda
Di recente ho provato a fare qualcosa di simile a questo:
a = "some string"
b = Proc.new{ upcase }
a.instance_eval b
Che dà l'errore:
TAYEERROR: Impossibile convertire Proc in String
Ma questo funziona:
def b(&block)
"some string".instance_eval &block
end
b{ upcase }
Un ulteriore sguardo con questo metodo:
def b(&block)
"some string".instance_eval block
end
Produce lo stesso Proc to String
errore.
Quindi ... la mia comprensione dei blocchi è che sono solo proc. Ma ovviamente c'è qualcosa di speciale nel avere questo &
ampersand ...
Qualcuno può spiegarmi questo? È possibile convertire un normale proc per essere qualunque cosa sia speciale in questo &block
oggetto?
modificare
Ho appena capito la mia seconda domanda, preparare un &
Al proc ... è stato facile, ma cosa sta davvero facendo?
Soluzione
Tutto quello che devi fare per il tuo primo esempio per lavorare è questo:
>> a.instance_eval &b #=> "SOME STRING"
Il motivo è quello instance_eval
Ha bisogno di una stringa o di un blocco e l'AmperSand fornisce quest'ultimo.
Per comprendere le differenze tra blocchi e proc, forse il seguente post sul blog aiuta:
Altri suggerimenti
La differenza è quella a.instance_eval b
sta passando b
Come argomento regolare a istanza_eval, mentre a.instance_eval &b
lo sta passando come un blocco. Quelle sono due cose diverse.
Considera questo metodo Call:
obj.foo(bar) do |x|
stuff(x)
end
Che invoca il metodo foo
con una discussione regolare (bar
) e un argomento di un blocco (do |x| stuff(x) end
). Nella definizione del metodo, si distinguono per prefisso &
al parametro di blocco:
def foo(arg, &block)
E se si desidera passare un'espressione variabile anziché un blocco letterale, che è anche realizzato dal prefisso & all'espressione (che dovrebbe produrre un proc).
Se passi una discussione con no &
, va nel arg slot invece del bloccare fessura. Non importa che l'argomento sia un'istanza di Proc. La sintassi determina come viene superata e trattata con il metodo.
È perché Instance_eval accetta una stringa per valutare o un blocco. instance_eval(&block)
sta passando il tuo block
come blocco a istanza_eval.
La differenza cruciale è quella Un'istanza Proc è un oggetto invece Un blocco non è un oggetto. Il &
è un operatore che scambia un blocco e un'istanza Proc reciprocamente.
Tutti gli argomenti a un metodo devono essere un oggetto. Oltre agli argomenti, un metodo può prendere un blocco. instance_eval
è un metodo che prende un argomento stringa o un blocco. Passare un oggetto Proc non soddisferà nessun caso. Se alleghi &
A un oggetto Proc, questo sarà gestito come un blocco.
Questo funzionerà:
a = "some string"
b = Proc.new{ upcase }
a.instance_eval &b
Il instance_eval
Il metodo può ricevere argomenti a blocchi.b
è un Proc
.