La OP escribió
Parece ser extraño para mí que la construcción anterior no produce el resultado esperado. ¿Cuál es el motivo para eso? ¿Cuáles son las situaciones cuando este comportamiento es razonable?
no '¿Se puede hacer?' pero para responder a la pregunta que no se pidió antes de llegar a la pregunta que en realidad se le preguntó:
$ irb
2.1.5 :001 > (0..4)
=> 0..4
2.1.5 :002 > (0..4).each { |i| puts i }
0
1
2
3
4
=> 0..4
2.1.5 :003 > (4..0).each { |i| puts i }
=> 4..0
2.1.5 :007 > (0..4).reverse_each { |i| puts i }
4
3
2
1
0
=> 0..4
2.1.5 :009 > 4.downto(0).each { |i| puts i }
4
3
2
1
0
=> 4
Desde reverse_each se demanda para construir toda una matriz, downto está claro que va a ser más eficiente. El hecho de que un diseñador de lenguaje incluso podría considerar la implementación de cosas así se relaciona con la respuesta a la pregunta real tal como se le preguntó.
Para responder a la pregunta en realidad se le preguntó ...
La razón se debe a que Ruby es un lenguaje infinitamente sorprendente. Algunas sorpresas son agradables, pero hay un montón de comportamientos que se rompen por completo. Incluso si algunos de estos ejemplos siguientes se corrigen por versiones más recientes, hay un montón de otros, y que permanecen como acusaciones en el modo de pensar del diseño original:
nil.to_s
.to_s
.inspect
resultados en "" pero
nil.to_s
# .to_s # Don't want this one for now
.inspect
resultados en
syntax error, unexpected '.', expecting end-of-input
.inspect
^
es probable que esperar < < y empuje a ser el mismo para anexar a las matrices, pero
a = []
a << *[:A, :B] # is illegal but
a.push *[:A, :B] # isn't.
Es probable que esperar 'grep' a comportarse como su equivalente de línea de comandos de Unix, pero sí === juego no = ~, a pesar de su nombre.
$ echo foo | grep .
foo
$ ruby -le 'p ["foo"].grep(".")'
[]
Varios métodos son inesperadamente alias de uno al otro, por lo que tiene que aprender varios nombres para la misma cosa - por ejemplo, find
y detect
- incluso si le gusta la mayoría de los desarrolladores y solo utiliza uno u otro. Lo mismo ocurre con size
, count
y length
, excepto las clases que definen cada una de manera diferente, o no definen una o dos en absoluto.
A menos que alguien haya implementado otra cosa, como el método central tap
se ha redefinido en varias bibliotecas de automatización para presionar algo en la pantalla. Buena suerte para descubrir qué está pasando, especialmente si algún módulo requerido por algún otro módulo ha monkeado otro módulo para hacer algo no documentado.
El objeto variable de entorno, ENV no apoyar 'fusión', por lo que tiene que escribir
ENV.to_h.merge('a': '1')
Como beneficio adicional, incluso se puede redefinir sus o de alguien más constantes si cambia de opinión acerca de lo que debiera ser.
No solo estoy interesado en cómo realizar esta iteración, que obviamente no es compatible, sino más bien por qué devuelve el rango 4..0. ¿Cuál fue la intención de los diseñadores de idiomas? ¿Por qué? ¿En qué situaciones es bueno? También vi un comportamiento similar en otras construcciones ruby, y todavía no está limpio cuando es útil. – fifigyuri
El rango en sí es devuelto por convención. Como la declaración '.each' no modificó nada, no hay un 'resultado' calculado para devolver. Cuando este es el caso, Ruby típicamente devuelve el objeto original en caso de éxito y 'nil' en error. Esto le permite usar expresiones como esta como condiciones en una instrucción 'if'. – bta