Um objeto do tipo Range representa valores entre um valor inicial e um valor final, retornando uma faixa/intervalo de valores. São escritos geralmente com dois ou três pontos entre esses valores. Se optarmos por usar dois pontos, o intervalo é inclusivo, isto é, o valor final faz parte da faixa retornada. E , por fim, se desejar utilizar dois pontos, a faixa será exclusiva e o valor final não fará parte da faixa retornada.
Para exemplicar o que acabei de escrever, nada mais do que a prática:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
ruby-1.9.2-p136 :015 > my_age = 1985..2011 => 1985..2011 ruby-1.9.2-p136 :016 > my_age.each do |year| ruby-1.9.2-p136 :017 > puts year ruby-1.9.2-p136 :018?> end 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 => 1985..2011 ruby-1.9.2-p136 :019 > my_age = 1985...2011 => 1985...2011 ruby-1.9.2-p136 :020 > my_age.each do |year| ruby-1.9.2-p136 :021 > puts year ruby-1.9.2-p136 :022?> end 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 => 1985...2011 |
ruby-1.9.2-p136 :015 > my_age = 1985..2011 => 1985..2011 ruby-1.9.2-p136 :016 > my_age.each do |year| ruby-1.9.2-p136 :017 > puts year ruby-1.9.2-p136 :018?> end 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 => 1985..2011 ruby-1.9.2-p136 :019 > my_age = 1985...2011 => 1985...2011 ruby-1.9.2-p136 :020 > my_age.each do |year| ruby-1.9.2-p136 :021 > puts year ruby-1.9.2-p136 :022?> end 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 => 1985...2011
-> Explico o que aconteceu.
É importante observar que a principal proposta de uma Range é a comparação, sendo capaz de identificar se um valor está dentro ou fora da faixa.
1 2 3 4 5 6 7 8 |
ruby-1.9.2-p136 :014 > (1..10) === 10 => true ruby-1.9.2-p136 :016 > (1...10) === 10 => false ruby-1.9.2-p136 :024 > (1...10).include?(5) => true ruby-1.9.2-p136 :025 > (1...10).include?(10) => false |
ruby-1.9.2-p136 :014 > (1..10) === 10 => true ruby-1.9.2-p136 :016 > (1...10) === 10 => false ruby-1.9.2-p136 :024 > (1...10).include?(5) => true ruby-1.9.2-p136 :025 > (1...10).include?(10) => false
Assume-se que na primeira linha, 10 está dentro da faixa de valores. Importante destacar que na segunda comparação
o 10 não se encontra mais nessa faixa de valores, pois a range foi declarada de forma exclusiva.
Uma outra grande observação é a iteração, como no exemplo abaixo, a classe dos desfechos de uma série define um método succ (para o sucessor), você verá um conjunto discreto de intervalos que podem ser iterados com each, step e alguns métodos da classe Enumerable.
1 2 3 4 5 6 7 8 |
ruby-1.9.2-p136 :001 > r = 'a'..'c' => "a".."c" ruby-1.9.2-p136 :004 > r.each {|l| print "[#{l}]"} [a][b][c] => "a".."c" ruby-1.9.2-p136 :005 > r.step(2) { |l| print "[#{l}]"} [a][c] => "a".."c" ruby-1.9.2-p136 :006 > r.to_a => ["a", "b", "c"] |
ruby-1.9.2-p136 :001 > r = 'a'..'c'
=> "a".."c"
ruby-1.9.2-p136 :004 > r.each {|l| print "[#{l}]"}
[a][b][c] => "a".."c"
ruby-1.9.2-p136 :005 > r.step(2) { |l| print "[#{l}]"}
[a][c] => "a".."c"
ruby-1.9.2-p136 :006 > r.to_a
=> ["a", "b", "c"]
A razão por esse código funcionar dessa maneira é que a classe String possui um método succ onde ‘a’.succ é igual ‘b’ e
‘b’.succ é igual a ‘c’.
Testando se existem membros em uma Range.
A classe Range possui métodos para determinar se um valor arbitrário é um membro de uma faixa (range). Existem duas formas de definir uma afiliação para as ranges, contínua ou discreta. A contínua seria algo equivalente a:
1 2 3 |
begin <= x <= end begin <= x < end # O que seria 1..3, por exemplo, com três pontos. |
begin <= x <= end begin <= x < end # O que seria 1..3, por exemplo, com três pontos.
Onde todos os valores finais dos intervalos devem implementar o operador <=>, portanto essa definição de filiação funciona para qualquer objeto Range e não necessita de valores finais para implementar o método succ .
A segunda forma de filiação, a discreta, necessita do succ. Ela lida com a classe Range como um conjunto que inclui o begin, begin.succ, begin.succ.succ e assim por diante. Por definição, uma range afiliada é um conjunto, onde o valor x é incluído em uma range apenas e somente se um valor é retornado por alguma das chamadas do método succ. Essa metodologia é muito mais custosa do que a contínua.
O exemplo abaixo exemplifica um teste com a forma discreta:
1 2 3 4 5 6 7 8 |
ruby-1.9.2-p136 :006 > r = 0...100 => 0...100 ruby-1.9.2-p136 :007 > r.member?50 => true ruby-1.9.2-p136 :008 > r.include?100 => false ruby-1.9.2-p136 :009 > r.include?99.9 => true |
ruby-1.9.2-p136 :006 > r = 0...100 => 0...100 ruby-1.9.2-p136 :007 > r.member?50 => true ruby-1.9.2-p136 :008 > r.include?100 => false ruby-1.9.2-p136 :009 > r.include?99.9 => true
Acredito que o artigo foi bem resumido, com a finalidade de que vocês, assim como eu, que estão estudando o Ruby possam encontrar mais informações a partir deste ou até mesmo trazer mais informações para este artigo a partir de outros!
A próxima cobertura será feita sobre os Symbols.
Portanto, nos vemos até o próximo post!
Abraços a todos!
