Diferença entre ‘..’ (ponto duplo) e ‘…’ (ponto triplo) na geração de intervalo?

Acabei de começar a aprender Ruby e Ruby on Rails e encontrei um código de validação que usa intervalos:

validates_inclusion_of :age, :in => 21..99 validates_exclusion_of :age, :in => 0...21, :message => "Sorry, you must be over 21" 

No começo eu pensei que a diferença estava na inclusão de endpoints, mas nos documentos da API que eu olhei, não parecia importar se era .. ou ... : sempre incluía os endpoints.

No entanto, fiz alguns testes em irb e pareceu indicar que .. inclui ambos os pontos finais, enquanto ... incluía apenas o limite inferior mas não o superior. Isso está correto?

A documentação do Range diz isto:

Ranges construídos usando .. correr desde o início até o fim, inclusive. Aqueles criados usando ... excluem o valor final.

Então a..b é como a <= x <= b , enquanto a...b é como a <= x < b .


Observe que, enquanto to_a em um intervalo de inteiros fornece uma coleção de inteiros, um intervalo não é um conjunto de valores, mas simplesmente um par de valores de início / fim:

 (1..5).include?(5) #=> true (1...5).include?(5) #=> false (1..4).include?(4.1) #=> false (1...5).include?(4.1) #=> true (1..4).to_a == (1...5).to_a #=> true (1..4) == (1...5) #=> false 

Os documentos usados ​​para não include isso, em vez disso, exigem a leitura da seção da Pickaxe em Ranges . Obrigado ao @MarkAmery ( veja abaixo ) por notar esta atualização.

Está correto.

 1.9.3p0 :005 > (1...10).to_a => [1, 2, 3, 4, 5, 6, 7, 8, 9] 1.9.3p0 :006 > (1..10).to_a => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

A syntax de ponto triplo é menos comum, mas é melhor que (1..10-1).to_a

Os documentos da API agora descrevem esse comportamento:

Ranges construídos usando .. correr desde o início até o fim, inclusive. Aqueles criados usando ... excluem o valor final.

http://ruby-doc.org/core-2.1.3/Range.html

Em outras palavras:

 2.1.3 :001 > ('a'...'d').to_a => ["a", "b", "c"] 2.1.3 :002 > ('a'..'d').to_a => ["a", "b", "c", "d"] 

a...b exclui o valor final, enquanto a..b inclui o valor final.

Ao trabalhar com inteiros, a...b se comporta como a..b-1 .

 >> (-1...3).to_a => [-1, 0, 1, 2] >> (-1..2).to_a => [-1, 0, 1, 2] >> (-1..2).to_a == (-1...3).to_a => true 

Mas realmente os intervalos diferem em uma linha numérica real .

 >> (-1..2) == (-1...3) => false 

Você pode ver isso ao incrementar etapas fracionárias.

 >> (-1..2).step(0.5).to_a => [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0] >> (-1...3).step(0.5).to_a => [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5] 

.. e … denota um intervalo.

Apenas veja em irb:

 ruby-1.9.2-p290 :032 > (1...2).each do puts "p" end p => 1...2 ruby-1.9.2-p290 :033 > (1..2).each do puts "p" end p p