Range 对象表现为一个间隔,有开始与结束的值集。 Range 对象可以由范围操作符 s..e 及 s…e 字面值,或者用 Range::new 构建。由 .. 操作符构建的 Range 对象包括范围的终点 end 值,而由 … 操作符构建的 Range 对象不包括范围的终点 end 值。当用于迭代器对象时, Range 对象返回序列内的每一个值。
例如:
for i in 1..5
…
end
生成从 1 到 5 的 Range 对象,然后对分别每个值进行迭代操作。
再如:
(-1..-5).to_a
#=> []
(-5..-1).to_a
#=> [-5, -4, -3, -2, -1]
('a'..'e').to_a
#=> ["a", "b", "c", "d", "e"]
('a'...'e').to_a
#=> ["a", "b", "c", "d"]
Range 对象可以由任何类型的对象构建,只要这个对象能够使用它们的 <=> 操作符,而且它们支持 succ 方法来返回序列内的下一个对象。也就是说,范围操作符的操作对象必须实现 <=> 比较操作,而且实现 succ 方法,则这个操作对象才能执行 Range#each 操作。
例如:
class Xs # 'x' 表示字符串
include Comparable
attr :length
def initialize(n)
@length = n
end
def succ #succ 方法的定义
Xs.new(@length + 1) # 生成新对象
end
def <=>(other) # 比较操作符的定义
@length <=> other.length
end
def to_s
sprintf "%2d #{inspect}", @length
end
def inspect
'x' * @length
end
end
r = Xs.new(3)..Xs.new(6) #=> xxx..xxxxxx
r.to_a
#=> [xxx, xxxx, xxxxx, xxxxxx]
r.member?(Xs.new(5)) #=> true
前面的例子中,类 Xs 包括了 Comparable 模块。这是因为 Enumerable#member? 使用 == 操作符检查等同性 (equality) 。包括 Comparable 可确保 == 操作符在实现 <=> 方法的 Xs 中被定义。
Range 类的超为是 Object ,同时它也包含了模块 Enumerable 。
类方法:
(1) Range.new(start, end, exclusive=false) => range 生成并返回一个从 start 到 end 间隔范围的 Range 对象。第三个参数若省略或为 false ,则 Range 对象包含终点 end 对象,否则,不包含终点 end 对象。生成对象时,会执行 start <=> end 操作以检查参数的合法性。若返回 nil ,则引发 ArgumentError 异常。
实例方法:
(1) rng === obj => true or false rng.member?(val) => true or false rng.include?(val) => true or false 若 val 在 Range 对象 rng 的范围内则返回真。 === 主要用在 case 句的比较中。
case 79
when 1..50
then
print "lown"
when 51..75
then
print "mediumn"
when 76..100 then
print "highn"
end
返回: high
p (0.1 .. 0.2).include?(0.15) # => true
p (0.1 .. 0.2).member?(0.15) # => cannot iterate from Float (TypeError)
# 比较字符串时, include? 将按照字典顺序进行比较
p ("a" .. "c").include?("ba") # => true
p ("a" .. "c").member?("ba") # => false
(2) rng.first => obj rng.begin => obj rng.end => obj rng.last => obj 返回 rng 中的 start 与 end 对象。 last 的返回值与 Range 对象是否包含范围的终点无关。
p (1.. 5).end # => 5
p (1... 5).end # => 5
(3) rng.exclude_end? => true or false rng 对象不包含范围终点时返回真。
(4) rng.each {| i | block } => rng 在 rng 对象的每个元素上进行迭代操作,传递每个值到 block 块中。你只可以在 Range 对象范围内的对象支持 succ 方法时进行迭代。 ( 这句话的意思是你不可以使用 Float 对象,因为它没有实现 succ 方法 ) 。
Range#each 使用各元素的 succ 方法进行迭代操作。截止 1.6 版本为止,对 Numeric 对象一直采用的是算术运算。正因为作出了这个变更,所以不得不修改 Float 中的 Range 的处理方法。 (Float 没有 succ) 。
(10..15).each do |n|
print n, ' '
end
produces: 10 11 12 13 14 15
(5) rng.step(n=1) {| obj | block } => rng 以 step 为步长对范围内的元素进行迭代操作。向 block 块传递每个 nth 元素。如果 Renge 对象的范围包含数字或字符串,则使用自然次序。否则 step 将调用 succ 方法来对范围内的元素进行迭代。 step 是正整数。默认值为 1 。
下面代码使用了前面的类 Xs 。
range = Xs.new(1)..Xs.new(10)
range.step(2) {|x| puts x}
range.step(3) {|x| puts x}
produces:
1 x
3 xxx
5 xxxxx
7 xxxxxxx
9 xxxxxxxxx
1 x
4 xxxx
7 xxxxxxx
10 xxxxxxxxxx
再如: ("a" .. "f").step(2) {|v| p v} # => "a" "c" "e"
(6) rng.to_s => string rng.inspect => string ruby 1.7 特性 :取消了 length 和 size 方法。若确实需要的话,可以这样
p ("a" .. "z").to_a.size #=> 26 即可。