¿Qué hace un operador doble * (splat)?

214

¿Has visto una función declarada así?

def foo a, **b
  ...
end

Entiendo que un solo *es el operador splat. Que hace** significa

Roy Lee
fuente

Respuestas:

373

Ruby 2.0 introdujo argumentos de palabras clave y **actúa como *, pero para argumentos de palabras clave. Devuelve un hash con pares clave / valor.

Para este código:

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

Aquí hay una demostración:

> 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}]
Dogbert
fuente
44
Esto responde a la pregunta perfectamente, pero tuve una adición menor. Así como el operador splat se puede usar en la matriz que se pasa, el splat doble se puede usar en hashes. Si opts = {d: 40, e: 50}, entonces foo 10, opts, f: 60asignará {f: 60}a c, mientras foo 10, **opts, f: 60que asignará {d: 40, e: 50, f: 60}. Para lograr el segundo efecto, previamente habría tenido merged las matrices explícitamente.
brymck
Supongo que esto es útil para establecer parámetros hash opcionales para un método
bigpotato
Probablemente valga la pena señalar que si se mezclan argumentos de palabras clave con splat de palabras clave, el splat de palabras clave debe aparecer después de los argumentos de palabras clave.
MrMesees
43

Ese es el doble splat operador de que está disponible desde Ruby 2.0.

Captura todos los argumentos de palabras clave (que también puede ser un simple hash, que era la forma idiomática de emular argumentos de palabras clave antes de que se convirtieran en parte del lenguaje Ruby)

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

my_method(key: "value")

El código anterior se imprime {key:value} en la consola.

Al igual que el operador splat único captura todos los argumentos regulares, pero en lugar de una matriz , obtiene un hash .

Ejemplo de la vida real:

Por ejemplo, en Rails, el cyclemétodo se ve así:

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

Este método se puede llamar así: cycle("red", "green", "blue", name: "colors") .

Este es un patrón bastante común: acepta una lista de argumentos y el último es un hash de opciones, que puede extraerse, por ejemplo, utilizando ActiveSupport extract_options!.

En Ruby 2.0 puede simplificar estos métodos:

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

Es cierto que solo es una mejora menor si ya está utilizando ActiveSupport, pero para Ruby, el código gana bastante concisión.

Daniel Rikowski
fuente
20

Además, puede usarlo en el lado de la persona que llama de esta manera:

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}
kuboon
fuente
55
Wow, doble splat es análogo al operador de propagación de objetos de ES6.
mpoisot
1
Gracias, esa es la confirmación que estaba buscando.
Qortex