2017-03-28 3 views
1

Ich stieß auf die &method in einer Codebasis und ich habe keine Ahnung, was vor sich geht. Dies geschieht in irb:Ruby & Method-Notation. Was ist los?

[12,3].map(&method(:to_s)) 
#=> ArgumentError: wrong number of arguments (given 1, expected 0) 
["12","3"].map(&method(:Integer)) 
#=> [12, 3] 

Was ist hier los?

Ich bin vertraut mit & gleich to_proc, aber ich kann immer noch nicht die Punkte hier anschließen.

Antwort

3

In &method(:to_s) wird .to_s aus dem aktuellen Kontext genommen (oberstes Objekt main). Diese Version ist bereits an den Empfänger gebunden und akzeptiert keine weiteren Argumente. Aber ein Argument wird von .map (jedes Element des Arrays) übergeben, das ist, was es tut.

Werfen Sie einen Blick auf diesen Schritt-für-Schritt-Rekonstruktion dessen, was

to_s # => "main" 
method(:to_s) # => #<Method: main.to_s> 
method(:to_s).to_proC# => #<Proc:0x007ff73a27e1e0 (lambda)> 
method(:to_s).to_proc.call(12) # => 
# ~> -:6:in `to_s': wrong number of arguments (given 1, expected 0) (ArgumentError) 
# ~> from -:6:in `<main>' 

Vergleichen Sie nun passiert, was passieren würde, wenn es .map(&:to_s)

:to_s.to_proc.call(12) # => "12" 

war, kam ich auf die &method in eine Codebasis

Es kann sein nützlich in Situationen wie diesem: Wenden Sie ein Stück Logik auf jedes Element an, aber diese Logik kommt aus dem aktuellen Kontext, komplett außerhalb der Elemente. Werfen Sie einen Blick auf diese erfundene Beispiel:

class Tweet 
    attr_accessor :text 

    def initialize(text) 
    @text = text 
    end 

    def shortened_links 
    find_links.map(&method(:shorten_link)) 
    # same as 
    # find_links.map {|link| shorten_link(link) } 
    end 

    private 

    def find_links 
    # detect links in text 
    end 

    def shorten_link(url) 
    # use bit.ly or whatever 
    end 
end 

Hier links eine Sammlung von Strings ist. Sie können sich sicherlich nicht verkürzen.

+0

Ich folge nicht ganz, warum 'method (: to_s) .to_proc.call (12)' einen Fehler auslöst, aber ': to_s.to_proc.call (12)' läuft ohne Fehler. – Jwan622

+0

@ Jwan622: weil es so funktioniert. '[12, 13] .map (&: to_s)' ist äquivalent zu '[12, 13] .map {| elem | elem.to_s} '. Dagegen ist '[12, 13] .map (& method (: to_s))' äquivalent zu '[12, 13] .map {| elem | to_s (elem)} '. Beachten Sie den Unterschied? –

+0

Und das ist nur die Regel der Sprache? Ist '12. & method (: to_s)' wirklich nur ein Wrapper über 'method (: to_s) .to_proc.call (12)'? Was löst "& Methode" auf jeden Fall? – Jwan622

1

Hier ist der Code, wo & wörtliche durch entsprechenden Block ersetzt:

[12,3].map { |v| to_s(v) } 

["12","3"].map { |v| Integer(v) } 

Wenn es in der Konsole genannt, to_s und Integer sind Methoden in Object Klasse. (Technisch Integer() ist von Kernel, die in Objekt enthalten ist).

to_sdefinition hat keine Argumente, deshalb erhalten Sie ArgumentError.

Integermethod könnte 1 oder 2 Argumente akzeptieren.