区间在Ruby代码中也很常见,通常区间的形式是(0..9),包含0到9之间的所有数字,包括9。也有另一种形式(0…10),包含0到10之间的所有数字,不包括10,即和前一种形式都包含0到9之间的所有数字,包括9。这种形式并不常见,但有时却非常有用。
有时候,使用不包含结尾的区间将更加简洁和直观。例如,eb_first…march_first可以更加简单的计算出今年二月的天数,同时,1…Float::INFINITY可以更加直观的表示出所有正整数,由于无穷大infinity不是一个数字。
区间是优秀的数据结构,因为它允许你定义一个巨大的集合而不需要在内存中实实在在的创造出整个集合。你必须小心你所使用的方法,因为某些区间操作可能导致整个集合被创建。
实例方法each显而易见会创造出整个区间,但这通常只会发生在每次使用第一个对象的时候,例如(1..Float::INFINITY).each {|i| puts i },在没有输出任何信息之前,事实上不可能用尽所有可用内存。区间对象中,mixin Enumerable所获得的方法依赖于each方法,所以它们也具有相同的行为。
区间有include?和cover?两个实例方法来测试一个值是否属于区间。include?方法使用each方法迭代整个区间来检测值是否存在于区间中,cover?方法只是简单比较值是否大于区间的开头,并且小于等于区间的结尾(对于不包含结尾元素的区间是小于区间的结尾)。这两个方法是不可以等价互换的,可能由于区间建立方式的不同和排序方式的不同,而导致意象不到的结果。
Ruby中许多类都可以进行区间操作,同样的,你也可以很容易地让自定义的类进行区间操作。
首先,你需要在类中实现称之为‘太空船’<=>操作符的方法。在这个方法中,如果other参数大于self返回-1,如果小于返回1,如果相等则返回0。一般情况下,如果比较是不合法的则返回nil。
下面的例子中,简单的代理了String#casecmp方法,这个实例方式是一个大小写不敏感的字符串比较方法,返回上面叙述的格式。
这样的话,你便可以创建一个区间,通过实例方法cover?测试成员关系,但这通常不是一种非常好的做法。
如果你想要迭代整个区间,生成一个数组,或者是使用实例方法include?测试成员关系,你需要实现succ方法,这个方法产生序列中的下一个对象。
你会注意到我同时也mixin了Comparable模块,这样在定义了实例方法<=>之后,类也拥有了实例方法==(同时也拥有了实例方法>,<等),而不是继承自Object类。
现在我们的区间将变得更加强大