web-dev-qa-db-fra.com

Que fait un opérateur double * (splat)

Avez-vous vu une fonction déclarée comme ça?

def foo a, **b
  ...
end

Je comprends qu’un seul * est l’opérateur Splat. Que signifie **?

196
Roy Lee

Ruby 2.0 a introduit les arguments de mots clés et ** agit comme *, mais pour les arguments de mots clés. Il retourne un hachage avec des paires clé/valeur.

Pour ce code:

def foo(a, *b, **c)
  [a, b, c]
end

Voici une démo:

> foo 10
=> [10, [], {}]
> foo 10, 20, 30
=> [10, [20, 30], {}]
> foo 10, 20, 30, d: 40, e: 50
=> [10, [20, 30], {:d=>40, :e=>50}]
> foo 10, d: 40, e: 50
=> [10, [], {:d=>40, :e=>50}]
345
Dogbert

C'est l'opérateur double splat qui est disponible depuis Ruby 2.0.

Il capture tout arguments de mots clés (qui peut également être un simple hachage, qui était le moyen idiomatique d'émuler des arguments de mots clés avant qu'ils ne fassent partie du langage Ruby).

def my_method(**options)
  puts options.inspect
end

my_method(key: "value")

Le code ci-dessus imprime {key:value} sur la console.

Tout comme l’opérateur single splat capture tous les arguments classiques, mais au lieu d’un tableau , vous obtenez un hachage .

Exemple réel:

Par exemple, dans Rails, la méthode cycle ressemble à ceci:

def cycle(first_value, *values)
  options = values.extract_options!
  # ...
end

Cette méthode peut s'appeler comme ceci: cycle("red", "green", "blue", name: "colors").

C'est un modèle assez courant: vous acceptez une liste d'arguments et le dernier est un hachage d'options, qui peut être extrait - par exemple - en utilisant le extract_options! d'ActiveSupport.

Dans Ruby 2.0, vous pouvez simplifier ces méthodes:

def cycle(first_value, *values, **options)
  # Same code as above without further changes!
end

Certes, ce n'est qu'une amélioration mineure si vous utilisez déjà ActiveSupport mais pour plain Ruby, le code gagne beaucoup de concision.

40
Daniel Rikowski

De plus, vous pouvez l’utiliser côté appelant comme ceci:

def foo(opts); p opts end
bar = {a:1, b:2}

foo(bar, c: 3)
=> ArgumentError: wrong number of arguments (given 2, expected 1)

foo(**bar, c: 3)
=> {:a=>1, :b=>2, :c=>3}
13
kuboon