2008-03-08

Range对象

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, ' '    endproduces: 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 即可。
EasyTime
评论
发表评论

提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则

您还没有登录,请登录后发表评论

litoueva
搜索本博客
最近加入圈子
存档
最新评论