2016-12-13 1 views
1

Je jouais autour de jruby irb et suis tombé sur ce phénomène où la méthode de paramètre retourne [[:rest]] quand elle est invoquée sur une méthode de chaîne. Ce n'est pas seulement le cas avec Strings mais je vais donner un exemple concernant les chaînes.Pourquoi Ruby génère-t-il [[: repos]] lorsque la méthode de paramètre est appelée sur les objets String?

irb(main):042:0> String.new.methods-Object.methods 
[:valid_encoding?, :casecmp, :to_java_bytes, :squeeze!, 
:is_utf8?, :slice, :hex, :[]=, :initialize_copy, :empty?, 
:oct, :rindex, :unseeded_hash, :%, :rjust, :chop, :index, 
:gsub!, :chomp!, :*, :+, :concat, :capitalize, :singularize, 
:titlecase, :each_line, :size, :deconstantize, :downcase!, 
:capitalize!, :to_sym, :humanize, :setbyte, :force_encoding, 
:sub, :reverse!, :swapcase, :scan, :gsub, :sum, :partition, 
:to_str, :codepoints, :swapcase!, :byteslice, :end_with?, 
:upto, :tr!, :[], :intern, :parameterize, :tableize, :chomp, 
:pluralize, :reverse, :mb_chars, :succ, :underscore, :titleize, 
:start_with?, :ljust, :tr, :chars, :chop!, :encode, :<<, 
:lstrip!, :dasherize, :prepend, :replace, :strip, :split, 
:to_i, :succ!, :to_f, :to_r, :rstrip!, :count, :to_c, :chr, 
:encoding, :camelcase, :slice!, :next!, :upcase, :bytesize, 
:demodulize, :delete!, :each_byte, :next, :classify, :squeeze, 
:downcase, :tr_s, :constantize, :crypt, :each_codepoint, 
:foreign_key, :insert, :delete, :camelize, :upcase!, :getbyte, 
:rpartition, :sub!, :unpack, :dump, :lines, :strip!, :ord, 
:safe_constantize, :center, :each_char, :match, :clear, 
:length, :to_java_string, :rstrip, :bytes, :ascii_only?, 
:tr_s!, :encode!, :lstrip, :to_json_raw, :to_json_raw_object, 
:included, :between?] 

Comme vous pouvez voir la liste ci-dessus montre les méthodes de la classe String, lorsque la méthode de paramètre est appelé sur l'une des méthodes ci-dessus donne la sortie # => [[:rest]]

irb(main):043:0> String.new.method(:each_line).parameters 
[[:rest]] 
irb(main):044:0> String.new.method(:slice).parameters 
[[:rest]] 

Un autre exemple en cas de une gemme nommée Sidekiq. Dans ce cas, il montre le nom de la classe de méthodes Stats avec rest.

irb(main):049:0> Sidekiq::Stats.new.methods-Object.methods 
[:scheduled_size, :enqueued, :failed, :processed, :default_queue_latency, :retry_size, :queues, :processes_size, :reset, :workers_size, :dead_size, :fetch_stats!] 
irb(main):050:0> Sidekiq::Stats.new.method(:reset).parameters 
[[:rest, :stats]] 

Quelqu'un peut-il expliquer ce rest fait référence dans ce cas?

Répondre

3

parameters vous donnera un tableau de paires, avec le premier élément étant un type de paramètre, et la seconde le nom de la variable qui l'acceptera. La plupart des paramètres ont le type :req, une variable obligatoire. Les paramètres optionnels, ceux avec la valeur par défaut, ont le type :opt. Et les paramètres définis avec un splat ont le type :rest: ces paramètres vont slurp up tous les paramètres supplémentaires au-delà du requis et optionnel. Il y a aussi le nouveau :keyrest, qui est le paramètre doublement splat.

def foo(a, b=3, *c, **d); end 
method(:foo).parameters 
# => [[:req, :a], [:opt, :b], [:rest, :c], [:keyrest, :d]] 

Si le paramètre reste est sans nom, vous obtenez seulement la valeur :rest au lieu d'une paire:

def bar(a, b=3, *); end 
method(:foo).parameters 
# => [[:req, :a], [:opt, :b], [:rest]] 

De nombreuses méthodes Ruby avec la mise en œuvre native ne sont pas définis avec la signature précise; le code C sous-jacent inspecte la liste de paramètres pour déterminer quel cas d'utilisation de la méthode a été invoqué. Ainsi, alors que dans Ruby String#each_line serait normalement fait comme ceci:

class String 
    def each_line(separator=$/) 
    #... 
    end 
end 

qui lui donnerait la signature [[:opt, :separator]], il est effectivement défini comme il a été écrit comme

class String 
    def each_line(*) 
    #... 
    end 
end