ruby - suma - ¿Por qué double splat solo funciona con las teclas de símbolo?
suma de arreglos ruby (2)
El operador de doble splat **
solo parece funcionar con hashes cuyas claves son símbolos. No funcionará cuando una clave es una cadena, por ejemplo. Esto es cierto para ambas formas; para construcción:
def foo **; end
foo(:a => 3) #=> nil
foo("a" => 3) #=> ArgumentError: wrong number of arguments (1 for 0)
y destrucción:
def bar *; end
bar(**{:a => 3}) #=> nil
bar(**{"a" => 3}) #=> TypeError: wrong argument type String (expected Symbol)
¿Por qué se limita a las teclas de símbolos?
Puede estar relacionado con el hecho de que la notación de palabra clave con nombre a: 3
coincide con la sintaxis de azúcar para el hash con teclas de símbolos, pero como se vio anteriormente, el splat doble funciona con la notación de hash ordinaria :a => 3
, por lo que no estoy seguro sobre esto.
La respuesta corta: así es como se expresan en Ruby los argumentos de palabras clave, que se supone que debe capturar el operador de doble splat.
La respuesta larga: el operador de doble splat es para capturar palabras clave como se ve en esta respuesta: https://.com/a/18289218/3644699
Desde Ruby 2.0, Ruby soporta verdaderos argumentos de palabras clave. Mi conjetura es que en la implementación principal todavía se representan como Hashes cuyas claves son símbolos, de forma similar a como se simularon antes de que el idioma los apoyara oficialmente.
Los errores particulares que está recibiendo probablemente dependen de la implementación. Por ejemplo, al ejecutar el último fragmento de código en irb, se muestra la función que genera el TypeError:
2.1.2 :001 > def bar *; end
=> :bar
2.1.2 :002 > bar(**{"a" => 3})
TypeError: wrong argument type String (expected Symbol)
from (irb):2:in `core#hash_merge_kwd''
from (irb):2
from /home/mkis/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>''
2.1.2 :003 >
hash_merge_kwd
es una función interna, definida aquí: https://github.com/ruby/ruby/blob/d738e3e15533e0f500789faaedcef9ed9ca362b9/vm.c#L2398
Me encontré con algo como esto recientemente.
Si está en Rails y tiene un método que toma argumentos de palabras clave y tiene un hash de params fuerte que desea enviarle, puede usar symbolize_keys
en el hash de params y se separará correctamente de los argumentos, sin duplicar. necesario.
Modelo
class ContactForm
def initialize(name:, email:)
@name = name
@email = email
end
# Other stuff
end
Controlador
class ContactController < ApplicationController
def send_mail
@contact_form = ContactForm.new(contact_params)
if @contact_form.submit
# Do stuff
end
end
def contact_params
params.require(:contact_form).permit(:name, :email).symbolize_keys
end
end