Ruby: Rango está vacía, pero con corte en rodajas que produce elementos
Pregunta
Estoy aprendiendo Ruby y acaba de conseguir en algunas cosas acerca de las matrices y rangos. Me he encontrado algo sobre rebanadas de que, si bien es lógico, a primera vista, me confunde un poco cuando miro profundamente en ella.
IRB dice que (2..-1).to_a
es una matriz vacía, es decir, no hay valores en el rango, ¿verdad?
Pero si uso ese mismo rango de [:a, :b, :c, :d, :e][2..-1]
, consigo [:c, :d, :e]
atrás en lugar de una matriz vacía.
Ahora, soy consciente de que -1 representa el último elemento de la matriz, por lo que tipo de sentido que lo que me recogieron, lo hizo. Pero si la estufa misma estaría vacía, ¿cómo es que la selección de cualquier cosa?
Solución
Esta es una pregunta fascinante. La respuesta es que no es los elementos individuales de la gama que son inspeccionados al rebanar la matriz, pero los elementos first
y last
. Específicamente:
>> (2..-1).to_a
=> []
>> (2..-1).first
=> 2
>> (2..-1).last
=> -1
Así los ejemplo funciona, ya que rebana la matriz desde el elemento [2]
al elemento [-1]
.
Si desea una forma coherente de pensar en esto, considere que (2..-1).to_a
salidas de los números enteros encuentra entre 2
y -1
(de los cuales hay ninguno), pero que los medios [2..-1]
del 2
index a la -1
index .
(Fuente:. array.c
y range.c
en la fuente de Rubí)
Y, la parte de bonificación complicado: para obtener el significado que estabas pensando, podría utilizar
>> [:a, :b, :c, :d, :e].values_at *(2..-1).to_a
=> []
Otros consejos
En la operación de corte no está viendo la gama como Range
per se, es solo mirar los valores de los puntos finales, en este caso 2
y -1
. Desde -1
tiene un significado especial (es decir, último elemento de la lista) simplemente devuelve todo, desde el elemento en la posición 2
al final de la lista. No pensar en él como un Range
aquí, sólo pensar en ella como una manera conveniente de pasar en dos números (que expresan dos puntos finales).
El método Array#[]
no utiliza el intervalo como un intervalo (es decir, que no llama include?
en él o algo por el estilo); sólo se necesita los dos números fuera de él y comprueba si es exclusiva.
Se puede imaginar a parecer algo como esto (aunque el []
real está implementado en C, no en Rubí , y por supuesto también maneja argumentos distintos rangos):
def [](range)
start = range.begin
length = range.end - start
length -= 1 if range.exclude_end?
slice(start, length)
end