¿Dónde es legal usar el operador ruby splat?
arrays syntax (2)
Los símbolos son geniales. No son solo para explotar matrices, aunque eso es divertido. También pueden enviarse a Array y aplanar arreglos (consulte http://github.com/mischa/splat/tree/master para obtener una lista exhaustiva de lo que hacen)
Parece que uno no puede realizar operaciones adicionales en el splat, pero en 1.8.6 / 1.9 el siguiente código lanza "tSTAR inesperado":
foo = bar || *zap #=> unexpected tSTAR
Considerando que esto funciona:
foo = *zap || bar #=> works, but of limited value
¿Dónde puede aparecer el símbolo en una expresión?
El "operador splat" en realidad no es un operador en absoluto, sino un token definido en la gramática de Ruby. Una lectura a través de gramática.y o la gramática de Ruby en formato BNF * le indicará que está permitido como el último o único argumento:
- en una definición de método (a excepción de un último
&foo
opcional) - en una llamada de método (a excepción de un último
&foo
opcional) - en el LHS de como asignación, por ejemplo:
a, b, *cs = [1,2,3,4]
- en la RHS de una asignación, por ejemplo:
a, b, c = 1, 2, *[3,4,5]
- en la cláusula when de una declaración de caso
Primero, la precedencia no es un problema aquí, porque foo = bar || (*zap)
foo = bar || (*zap)
no funciona mejor. La regla general es que no puede realizar operaciones adicionales en un splat. Incluso algo tan simple como foo = (*zap)
no es válido. Esto se aplica a 1.9 también.
Habiendo dicho eso, ¿qué esperas foo = bar || *zap
foo = bar || *zap
a hacer, si funcionó, eso es diferente a foo = bar || zap
foo = bar || zap
Incluso en un caso como a, b = bar || *zap
a, b = bar || *zap
(que tampoco funciona), a, b = bar || zap
a, b = bar || zap
logra lo que yo asumiría que sería lo mismo.
La única situación en la que esto podría tener algún sentido es algo como a, b = foo, bar || *zap
a, b = foo, bar || *zap
. Debería encontrar que la mayoría de los casos en los que desearía usar esto están cubiertos por a, b = foo, *(bar || zap)
. Si eso no cubre tu caso, probablemente deberías preguntarte qué es lo que realmente esperas lograr al escribir una construcción tan fea.
EDITAR:
En respuesta a tus comentarios, *zap || bar
*zap || bar
es equivalente a *(zap || bar)
. Esto demuestra cuán baja es la precedencia del splat. ¿Exactamente qué tan bajo es? La mejor respuesta que puedo darte es "bastante baja".
Para un ejemplo interesante, sin embargo, considere un método foo
que toma tres argumentos:
def foo(a, b, c)
#important stuff happens here!
end
foo(*bar = [1, 2, 3])
salpicará después de la asignación y establecerá los argumentos en 1, 2 y 3 respectivamente. Compare eso con foo((*bar = [1, 2, 3]))
que se quejará de tener el número incorrecto de argumentos (1 para 3).