ruby arrays syntax precedence splat

¿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).