O que um operador duplo * (splat) faz

214

Você viu uma função declarada assim?

def foo a, **b
  ...
end

Eu entendo que um único *é o operador splat. O que **significa isso ?

Roy Lee
fonte

Respostas:

373

O Ruby 2.0 introduziu argumentos de palavras-chave e **age como *, mas para argumentos de palavras-chave. Retorna um Hash com pares chave / valor.

Para este código:

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

Aqui está uma demonstração:

> 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
fonte
44
Isso responde perfeitamente à pergunta, mas eu tive um pequeno adendo. Assim como o operador de splat pode ser usado na matriz que você passa, o splat duplo pode ser usado em hashes. Se opts = {d: 40, e: 50}, então foo 10, opts, f: 60atribuirá {f: 60}a c, enquanto foo 10, **opts, f: 60atribuirá {d: 40, e: 50, f: 60}. Para alcançar o segundo efeito, anteriormente você teria mergeas matrizes explicitamente.
brymck
Eu diria que este é útil para definir os parâmetros de hash opcionais para um método
bigpotato
Provavelmente vale a pena observar que, se você misturar argumentos de palavra-chave com splat de palavras-chave, o splat de palavras-chave precisará vir após os argumentos de palavra-chave.
MrMesees 04/04/19
43

Esse é o operador de splat duplo que está disponível desde o Ruby 2.0.

Ele captura todos os argumentos de palavras-chave (que também podem ser um hash simples, que era a maneira idiomática de emular argumentos de palavras-chave antes que eles se tornassem parte da linguagem Ruby)

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

my_method(key: "value")

O código acima é impresso {key:value}no console.

Assim como o operador splat único captura todos os argumentos regulares, mas em vez de uma matriz, você obtém um hash .

Exemplo da vida real:

Por exemplo, no Rails, o cyclemétodo se parece com isso:

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

Este método pode ser chamado assim: cycle("red", "green", "blue", name: "colors").

Esse é um padrão bastante comum: você aceita uma lista de argumentos e o último é um hash de opções, que pode ser extraído - por exemplo - usando os do ActiveSupport extract_options!.

No Ruby 2.0, você pode simplificar estes métodos:

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

É certo que é apenas uma pequena melhoria se você já estiver usando o ActiveSupport, mas para Ruby comum o código ganha bastante concisão.

Daniel Rikowski
fonte
20

Além disso, você pode usá-lo no lado do chamador assim:

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
fonte
5
Uau, o splat duplo é análogo ao operador de propagação de objetos do ES6.
precisa saber é
1
Obrigado, essa é a confirmação que eu estava procurando.
Qortex 25/10/19