[ruby] Ruby中的Range(范围)

37 阅读2分钟

定义

Range代表’连续‘值的集合。集合中值的范围由Range的起始值和结束值标记。这里的’连续’并非数学中的连续,在读完文章后,相信你会对这个‘连续’有清楚的认识。

创建Range

Ruby提供了2种方式创建Range:

  1. 常量方式:(1..4) 表示1,2,3,4构成的值集合;(1...4)表示1,2,3构成的值集合。
  2. 对象方式:Range.new(1,4)表示1,2,3,4构成的值集合;Range.new(1,4,true)表示1,2,3构成的值集合。

从上述创建Range的方式中,可以看到,..(两个点)表示包括结束值,...(三个点)表示不包括结束值。(1..4)Range.new(1,4)效果一样;(1...4)Range.new(1,4,true)效果一样,true表示不包括结束值。

Range分类

有开始值/结束值的Range

这类Range有明确的边界,如: (1..4),开始值是1,结束值是4.

没有开始值的Range

(..4)Range.new(nil, 4)效果一样,表示的都是nil..4范围;(...4)Range.new(nil, 4, true)效果一样,表示的都是nil...4范围。这类Range通常用来做数组切片(slice),如:

a = [1, 2, 3, 4]
r = (...2) # => nil...2
a[r]      # => [1, 2]

 没有结束值的Range

(1..)Range.new(1, nil)效果一样,表示的都是1..范围;(1...)Range.new(1, nil, true)效果一样,表示的都是1...范围。这类Range通常用来做数组切片(slice),如:

a = [1, 2, 3, 4]
r = (2..) # => 2..
a[r]      # => [3, 4]

注意,针对(1..)(1...)这2种没有结束值的Range,他们的起始值、结束值都相同,但是这2个Range是不同的,如:

r0 = (1..)           # => 1..
r1 = (1...)          # => 1...
r0.begin == r1.begin # => true
r0.end == r1.end     # => true
r0 == r1             # => false

可放入Range的对象

如果一个对象可以放入Range中,这个对象的类一定实现了实例方法<=>

  1. Ruby中的核心类:Array,String,Time,Integer,Float,Symbol,Numeric,Rational,Complex,Kernel,Module,File::State均实现了<=>方法。

  2. 自定义类

    t0 = Time.now # => 2021-09-19 09:22:48.4854986 -0500 t1 = Time.now # => 2021-09-19 09:22:56.0365079 -0500 t2 = Time.now # => 2021-09-19 09:23:08.5263283 -0500 (t0..t2).include?(t1) # => true (t0..t1).include?(t2) # => false

可被迭代的Range

如果一个Range可被迭代,那么Range中的对象的类一定实现了实例方法succ

Ruby的核心类中,只有Integer,String和Symbol实现了succ实例方法。上述提到的其他Ruby核心类,并没有实现succ实例方法,因此不能被迭代。

Reference

Ruby API - Range(3.2)