类 Range
Range 对象表示给定起始值和结束值之间的值的集合。
您可以使用以下方式显式创建一个 Range 对象:
-
# Ranges that use '..' to include the given end value. (1..4).to_a # => [1, 2, 3, 4] ('a'..'d').to_a # => ["a", "b", "c", "d"] # Ranges that use '...' to exclude the given end value. (1...4).to_a # => [1, 2, 3] ('a'...'d').to_a # => ["a", "b", "c"]
-
# 默认包含给定结束值的范围。
Range.new(1, 4).to_a # => [1, 2, 3, 4]Range.new('a', 'd').to_a # => ["a", "b", "c", "d"] # 使用第三个参数exclude_end排除给定结束值的范围。Range.new(1, 4, true).to_a # => [1, 2, 3]Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
无始范围¶ ↑
一个无始范围具有确定的结束值,但起始值为 nil。这样的范围包含所有直到结束值的值。
r = (..4) # => nil..4 r.begin # => nil r.include?(-50) # => true r.include?(4) # => true r = (...4) # => nil...4 r.include?(4) # => false Range.new(nil, 4) # => nil..4 Range.new(nil, 4, true) # => nil...4
无始范围可用于切片数组
a = [1, 2, 3, 4] # Include the third array element in the slice r = (..2) # => nil..2 a[r] # => [1, 2, 3] # Exclude the third array element from the slice r = (...2) # => nil...2 a[r] # => [1, 2]
无始范围的 each 方法会引发异常。
无终范围¶ ↑
一个无终范围具有确定的起始值,但结束值为 nil。这样的范围包含从起始值开始的所有值。
r = (1..) # => 1.. r.end # => nil r.include?(50) # => true Range.new(1, nil) # => 1..
无终范围的字面量可以用两个点或三个点表示。无论哪种方式,范围都具有相同的元素。但请注意,两者不相等。
r0 = (1..) # => 1.. r1 = (1...) # => 1... r0.begin == r1.begin # => true r0.end == r1.end # => true r0 == r1 # => false
无终范围可用于切片数组
a = [1, 2, 3, 4] r = (2..) # => 2.. a[r] # => [3, 4]
无终范围的 each 方法会无限期地调用给定的块。
a = [] r = (1..) r.each do |i| a.push(i) if i.even? break if i > 10 end a # => [2, 4, 6, 8, 10]
一个范围可以既无始又无终。对于字面量的无始无终范围,至少范围的开头或结尾必须作为显式的 nil 值给出。建议使用显式的 nil 开头和隐式的 nil 结尾,因为这是 Ruby 用于 Range#inspect 的方式。
(nil..) # => (nil..) (..nil) # => (nil..) (nil..nil) # => (nil..)
范围与其他类¶ ↑
如果一个对象的类实现了实例方法 #<=>,则该对象可以放入范围中。实现此方法的 Ruby 核心类包括 Array、Complex、File::Stat、Float、Integer、Kernel、Module、Numeric、Rational、String、Symbol 和 Time。
示例
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
仅当范围的元素实现了实例方法 succ 时,才能对范围进行迭代。实现此方法的 Ruby 核心类包括 Integer、String 和 Symbol(但不包括上面提到的其他类)。
迭代器方法包括:
-
从模块 Enumerable 中包含:
each_entry、each_with_index、each_with_object、each_slice、each_cons和reverse_each。
示例
a = [] (1..4).each {|i| a.push(i) } a # => [1, 2, 3, 4]
范围和用户自定义类¶ ↑
要在范围中使用的用户自定义类必须实现实例方法 #<=>;请参阅 Integer#<=>。要使迭代可用,它还必须实现实例方法 succ;请参阅 Integer#succ。
下面的类同时实现了 #<=> 和 succ,因此既可用于构造范围,也可用于迭代范围。请注意,包含了 Comparable 模块,因此 == 方法是根据 #<=> 定义的。
# Represent a string of 'X' characters. class Xs include Comparable attr_accessor :length def initialize(n) @length = n end def 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.include?(Xs.new(5)) #=> true r.include?(Xs.new(7)) #=> false
这里有什么¶ ↑
首先,看看其他地方有什么。类 Range:
-
继承自 类 Object。
-
包含 模块 Enumerable,该模块提供了数十种其他方法。
在这里,类 Range 提供了以下有用的方法:
创建范围的方法¶ ↑
-
::new:返回一个新的范围。
查询方法¶ ↑
-
begin:返回为self给定的起始值。 -
bsearch:返回由二分搜索从self中选择的元素。 -
count:返回self中元素的计数。 -
end:返回为self给定的结束值。 -
exclude_end?:返回是否排除结束对象。 -
first:返回self的第一个元素。 -
hash:返回整数哈希码。 -
last:返回self的最后一个元素。 -
max:返回self中的最大值。 -
min:返回self中的最小值。 -
minmax:返回self中的最小值和最大值。 -
size:返回self中元素的计数。
比较方法¶ ↑
迭代方法¶ ↑
转换方法¶ ↑
处理 JSON 的方法¶ ↑
-
::json_create:返回从给定对象构造的新 Range 对象。
-
as_json:返回表示
self的 2 元素哈希。 -
to_json:返回表示
self的 JSON 字符串。
要使这些方法可用:
require 'json/add/range'
公共类方法
返回基于给定对象 begin 和 end 的新范围。可选参数 exclude_end 确定对象 end 是否作为范围中的最后一个对象包含。
Range.new(2, 5).to_a # => [2, 3, 4, 5] Range.new(2, 5, true).to_a # => [2, 3, 4] Range.new('a', 'd').to_a # => ["a", "b", "c", "d"] Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
static VALUE
range_initialize(int argc, VALUE *argv, VALUE range)
{
VALUE beg, end, flags;
rb_scan_args(argc, argv, "21", &beg, &end, &flags);
range_modify(range);
range_init(range, beg, end, RBOOL(RTEST(flags)));
return Qnil;
}
公共实例方法
与 step 相同(但未提供 n 的默认值)。此方法对于表达性地生成 Enumerator::ArithmeticSequence 很方便。
array = [0, 1, 2, 3, 4, 5, 6] # slice each second element: seq = (0..) % 2 #=> ((0..).%(2)) array[seq] #=> [0, 2, 4, 6] # or just array[(0..) % 2] #=> [0, 2, 4, 6]
请注意,由于 Ruby 中的运算符优先级,在这种情况下,范围周围必须使用括号
(0..7) % 2 #=> ((0..7).%(2)) -- as expected 0..7 % 2 #=> 0..1 -- parsed as 0..(7 % 2)
static VALUE
range_percent_step(VALUE range, VALUE step)
{
return range_step(1, &step, range);
}
当且仅当满足以下条件时,返回 true:
-
other是一个范围。 -
other.begin == self.begin. -
other.end == self.end. -
other.exclude_end? == self.exclude_end?.
否则返回 false。
r = (1..5) r == (1..5) # => true r = Range.new(1, 5) r == 'foo' # => false r == (2..5) # => false r == (1..4) # => false r == (1...5) # => false r == Range.new(1, 5, true) # => false
请注意,即使使用相同的参数,== 和 eql? 的返回值也可能不同。
(1..2) == (1..2.0) # => true (1..2).eql? (1..2.0) # => false
相关:Range#eql?。
static VALUE
range_eq(VALUE range, VALUE obj)
{
if (range == obj)
return Qtrue;
if (!rb_obj_is_kind_of(obj, rb_cRange))
return Qfalse;
return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
}
如果 object 在 self.begin 和 self.end 之间,则返回 true。否则返回 false
(1..4) === 2 # => true (1..4) === 5 # => false (1..4) === 'a' # => false (1..4) === 4 # => true (1...4) === 4 # => false ('a'..'d') === 'c' # => true ('a'..'d') === 'e' # => false
case 语句使用方法 ===,因此:
case 79 when (1..50) "low" when (51..75) "medium" when (76..100) "high" end # => "high" case "2.6.5" when ..."2.4" "EOL" when "2.4"..."2.5" "maintenance" when "2.5"..."3.0" "stable" when "3.1".. "upcoming" end # => "stable"
static VALUE
range_eqq(VALUE range, VALUE val)
{
return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
}
返回定义 self 开头的对象。
(1..4).begin # => 1 (..2).begin # => nil
相关: Range#first, Range#end.
static VALUE
range_begin(VALUE range)
{
return RANGE_BEG(range);
}
返回通过二分查找从 self 中选择的元素。
请参阅 二分查找。
static VALUE
range_bsearch(VALUE range)
{
VALUE beg, end, satisfied = Qnil;
int smaller;
/* Implementation notes:
* Floats are handled by mapping them to 64 bits integers.
* Apart from sign issues, floats and their 64 bits integer have the
* same order, assuming they are represented as exponent followed
* by the mantissa. This is true with or without implicit bit.
*
* Finding the average of two ints needs to be careful about
* potential overflow (since float to long can use 64 bits).
*
* The half-open interval (low, high] indicates where the target is located.
* The loop continues until low and high are adjacent.
*
* -1/2 can be either 0 or -1 in C89. However, when low and high are not adjacent,
* the rounding direction of mid = (low + high) / 2 does not affect the result of
* the binary search.
*
* Note that -0.0 is mapped to the same int as 0.0 as we don't want
* (-1...0.0).bsearch to yield -0.0.
*/
#define BSEARCH(conv, excl) \
do { \
RETURN_ENUMERATOR(range, 0, 0); \
if (!(excl)) high++; \
low--; \
while (low + 1 < high) { \
mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
: (low + high) / 2; \
BSEARCH_CHECK(conv(mid)); \
if (smaller) { \
high = mid; \
} \
else { \
low = mid; \
} \
} \
return satisfied; \
} while (0)
#define BSEARCH_FIXNUM(beg, end, excl) \
do { \
long low = FIX2LONG(beg); \
long high = FIX2LONG(end); \
long mid; \
BSEARCH(INT2FIX, (excl)); \
} while (0)
beg = RANGE_BEG(range);
end = RANGE_END(range);
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
BSEARCH_FIXNUM(beg, end, EXCL(range));
}
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
int64_t mid;
BSEARCH(int64_as_double_to_num, EXCL(range));
}
#endif
else if (is_integer_p(beg) && is_integer_p(end)) {
RETURN_ENUMERATOR(range, 0, 0);
return bsearch_integer_range(beg, end, EXCL(range));
}
else if (is_integer_p(beg) && NIL_P(end)) {
VALUE diff = LONG2FIX(1);
RETURN_ENUMERATOR(range, 0, 0);
while (1) {
VALUE mid = rb_funcall(beg, '+', 1, diff);
BSEARCH_CHECK(mid);
if (smaller) {
if (FIXNUM_P(beg) && FIXNUM_P(mid)) {
BSEARCH_FIXNUM(beg, mid, false);
}
else {
return bsearch_integer_range(beg, mid, false);
}
}
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
beg = mid;
}
}
else if (NIL_P(beg) && is_integer_p(end)) {
VALUE diff = LONG2FIX(-1);
RETURN_ENUMERATOR(range, 0, 0);
while (1) {
VALUE mid = rb_funcall(end, '+', 1, diff);
BSEARCH_CHECK(mid);
if (!smaller) {
if (FIXNUM_P(mid) && FIXNUM_P(end)) {
BSEARCH_FIXNUM(mid, end, false);
}
else {
return bsearch_integer_range(mid, end, false);
}
}
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
end = mid;
}
}
else {
rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
}
return range;
}
返回基于给定参数或代码块条件(如果给定)的元素计数。
如果没有给定参数和代码块,则返回元素的数量。
(1..4).count # => 4 (1...4).count # => 3 ('a'..'d').count # => 4 ('a'...'d').count # => 3 (1..).count # => Infinity (..4).count # => Infinity
如果给定参数 object,则返回在 self 中找到的 object 的数量,通常为零或一。
(1..4).count(2) # => 1 (1..4).count(5) # => 0 (1..4).count('a') # => 0
如果给定代码块,则为每个元素调用该代码块;返回代码块返回真值的元素的数量。
(1..4).count {|element| element < 3 } # => 2
相关: Range#size.
static VALUE
range_count(int argc, VALUE *argv, VALUE range)
{
if (argc != 0) {
/* It is odd for instance (1...).count(0) to return Infinity. Just let
* it loop. */
return rb_call_super(argc, argv);
}
else if (rb_block_given_p()) {
/* Likewise it is odd for instance (1...).count {|x| x == 0 } to return
* Infinity. Just let it loop. */
return rb_call_super(argc, argv);
}
VALUE beg = RANGE_BEG(range), end = RANGE_END(range);
if (NIL_P(beg) || NIL_P(end)) {
/* We are confident that the answer is Infinity. */
return DBL2NUM(HUGE_VAL);
}
if (is_integer_p(beg)) {
VALUE size = range_size(range);
if (!NIL_P(size)) {
return size;
}
}
return rb_call_super(argc, argv);
}
如果给定参数在 self 范围内,则返回 true,否则返回 false。
对于非范围参数 object,使用 <= 和 < 进行评估。
对于包含结束值(#exclude_end? == false)的范围 self,按如下方式评估:
self.begin <= object <= self.end
示例
r = (1..4) r.cover?(1) # => true r.cover?(4) # => true r.cover?(0) # => false r.cover?(5) # => false r.cover?('foo') # => false r = ('a'..'d') r.cover?('a') # => true r.cover?('d') # => true r.cover?(' ') # => false r.cover?('e') # => false r.cover?(0) # => false
对于排除结束值(#exclude_end? == true)的范围 r,按如下方式评估:
r.begin <= object < r.end
示例
r = (1...4) r.cover?(1) # => true r.cover?(3) # => true r.cover?(0) # => false r.cover?(4) # => false r.cover?('foo') # => false r = ('a'...'d') r.cover?('a') # => true r.cover?('c') # => true r.cover?(' ') # => false r.cover?('d') # => false r.cover?(0) # => false
对于范围参数 range,比较 self 和 range 的第一个和最后一个元素
r = (1..4) r.cover?(1..4) # => true r.cover?(0..4) # => false r.cover?(1..5) # => false r.cover?('a'..'d') # => false r = (1...4) r.cover?(1..3) # => true r.cover?(1..4) # => false
如果起始和结束是数值型的,cover? 的行为类似于 include?
(1..3).cover?(1.5) # => true (1..3).include?(1.5) # => true
但当不是数值型时,这两个方法可能会有所不同
('a'..'d').cover?('cc') # => true ('a'..'d').include?('cc') # => false
如果以下任一情况成立,则返回 false:
-
self的起始值大于其结束值。 -
对
#<=>的内部调用返回nil;也就是说,操作数不可比较。
无起始范围覆盖结束之前的所有相同类型的值,排除独占范围的结束值。无起始范围覆盖在无起始范围结束之前的范围,或者对于包含范围,覆盖到无起始范围的末尾。
(..2).cover?(1) # => true (..2).cover?(2) # => true (..2).cover?(3) # => false (...2).cover?(2) # => false (..2).cover?("2") # => false (..2).cover?(..2) # => true (..2).cover?(...2) # => true (..2).cover?(.."2") # => false (...2).cover?(..2) # => false
无结束范围覆盖起始之后的所有相同类型的值。无结束的独占范围不覆盖无结束的包含范围。
(2..).cover?(1) # => false (2..).cover?(3) # => true (2...).cover?(3) # => true (2..).cover?(2) # => true (2..).cover?("2") # => false (2..).cover?(2..) # => true (2..).cover?(2...) # => true (2..).cover?("2"..) # => false (2...).cover?(2..) # => false (2...).cover?(3...) # => true (2...).cover?(3..) # => false (3..).cover?(2..) # => false
既无起始也无结束的范围覆盖所有值和范围,并对所有参数返回 true,例外情况是无起始和无结束的独占范围不覆盖无结束的包含范围。
(nil...).cover?(Object.new) # => true (nil...).cover?(nil...) # => true (nil..).cover?(nil...) # => true (nil...).cover?(nil..) # => false (nil...).cover?(1..) # => false
相关: Range#include?.
static VALUE
range_cover(VALUE range, VALUE val)
{
VALUE beg, end;
beg = RANGE_BEG(range);
end = RANGE_END(range);
if (rb_obj_is_kind_of(val, rb_cRange)) {
return RBOOL(r_cover_range_p(range, beg, end, val));
}
return r_cover_p(range, beg, end, val);
}
如果给定代码块,则将 self 的每个元素传递给该代码块
a = [] (1..4).each {|element| a.push(element) } # => 1..4 a # => [1, 2, 3, 4]
除非 self.first.respond_to?(:succ),否则引发异常。
如果没有给定代码块,则返回一个枚举器。
static VALUE
range_each(VALUE range)
{
VALUE beg, end;
long i;
RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
beg = RANGE_BEG(range);
end = RANGE_END(range);
if (FIXNUM_P(beg) && NIL_P(end)) {
range_each_fixnum_endless(beg);
}
else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
return range_each_fixnum_loop(beg, end, range);
}
else if (RB_INTEGER_TYPE_P(beg) && (NIL_P(end) || RB_INTEGER_TYPE_P(end))) {
if (SPECIAL_CONST_P(end) || RBIGNUM_POSITIVE_P(end)) { /* end >= FIXNUM_MIN */
if (!FIXNUM_P(beg)) {
if (RBIGNUM_NEGATIVE_P(beg)) {
do {
rb_yield(beg);
} while (!FIXNUM_P(beg = rb_big_plus(beg, INT2FIX(1))));
if (NIL_P(end)) range_each_fixnum_endless(beg);
if (FIXNUM_P(end)) return range_each_fixnum_loop(beg, end, range);
}
else {
if (NIL_P(end)) range_each_bignum_endless(beg);
if (FIXNUM_P(end)) return range;
}
}
if (FIXNUM_P(beg)) {
i = FIX2LONG(beg);
do {
rb_yield(LONG2FIX(i));
} while (POSFIXABLE(++i));
beg = LONG2NUM(i);
}
ASSUME(!FIXNUM_P(beg));
ASSUME(!SPECIAL_CONST_P(end));
}
if (!FIXNUM_P(beg) && RBIGNUM_SIGN(beg) == RBIGNUM_SIGN(end)) {
if (EXCL(range)) {
while (rb_big_cmp(beg, end) == INT2FIX(-1)) {
rb_yield(beg);
beg = rb_big_plus(beg, INT2FIX(1));
}
}
else {
VALUE c;
while ((c = rb_big_cmp(beg, end)) != INT2FIX(1)) {
rb_yield(beg);
if (c == INT2FIX(0)) break;
beg = rb_big_plus(beg, INT2FIX(1));
}
}
}
}
else if (SYMBOL_P(beg) && (NIL_P(end) || SYMBOL_P(end))) { /* symbols are special */
beg = rb_sym2str(beg);
if (NIL_P(end)) {
rb_str_upto_endless_each(beg, sym_each_i, 0);
}
else {
rb_str_upto_each(beg, rb_sym2str(end), EXCL(range), sym_each_i, 0);
}
}
else {
VALUE tmp = rb_check_string_type(beg);
if (!NIL_P(tmp)) {
if (!NIL_P(end)) {
rb_str_upto_each(tmp, end, EXCL(range), each_i, 0);
}
else {
rb_str_upto_endless_each(tmp, each_i, 0);
}
}
else {
if (!discrete_object_p(beg)) {
rb_raise(rb_eTypeError, "can't iterate from %s",
rb_obj_classname(beg));
}
if (!NIL_P(end))
range_each_func(range, each_i, 0);
else
for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
rb_yield(beg);
}
}
return range;
}
返回定义 self 结尾的对象。
(1..4).end # => 4 (1...4).end # => 4 (1..).end # => nil
相关: Range#begin, Range#last.
static VALUE
range_end(VALUE range)
{
return RANGE_END(range);
}
返回一个包含 self 中元素的数组(如果是一个有限集合);否则会引发异常。
(1..4).to_a # => [1, 2, 3, 4] (1...4).to_a # => [1, 2, 3] ('a'..'d').to_a # => ["a", "b", "c", "d"]
当且仅当满足以下条件时,返回 true:
-
other是一个范围。 -
other.begin.eql?(self.begin). -
other.end.eql?(self.end). -
other.exclude_end? == self.exclude_end?.
否则返回 false。
r = (1..5) r.eql?(1..5) # => true r = Range.new(1, 5) r.eql?('foo') # => false r.eql?(2..5) # => false r.eql?(1..4) # => false r.eql?(1...5) # => false r.eql?(Range.new(1, 5, true)) # => false
请注意,即使使用相同的参数,== 和 eql? 的返回值也可能不同。
(1..2) == (1..2.0) # => true (1..2).eql? (1..2.0) # => false
相关: Range#==.
static VALUE
range_eql(VALUE range, VALUE obj)
{
if (range == obj)
return Qtrue;
if (!rb_obj_is_kind_of(obj, rb_cRange))
return Qfalse;
return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
}
如果 self 排除其结束值,则返回 true;否则返回 false。
Range.new(2, 5).exclude_end? # => false Range.new(2, 5, true).exclude_end? # => true (2..5).exclude_end? # => false (2...5).exclude_end? # => true
static VALUE
range_exclude_end_p(VALUE range)
{
return RBOOL(EXCL(range));
}
如果没有参数,则返回 self 的第一个元素(如果存在)
(1..4).first # => 1 ('a'..'d').first # => "a"
如果给定非负整数参数 n,则返回数组中的前 n 个元素
(1..10).first(3) # => [1, 2, 3] (1..10).first(0) # => [] (1..4).first(50) # => [1, 2, 3, 4]
如果不存在第一个元素,则引发异常
(..4).first # Raises RangeError
static VALUE
range_first(int argc, VALUE *argv, VALUE range)
{
VALUE n, ary[2];
if (NIL_P(RANGE_BEG(range))) {
rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
}
if (argc == 0) return RANGE_BEG(range);
rb_scan_args(argc, argv, "1", &n);
ary[0] = n;
ary[1] = rb_ary_new2(NUM2LONG(n));
rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
return ary[1];
}
返回 self 的整数哈希值。当且仅当 r0.eql?(r1) 时,两个范围对象 r0 和 r1 具有相同的哈希值。
相关: Range#eql?, Object#hash.
static VALUE
range_hash(VALUE range)
{
st_index_t hash = EXCL(range);
VALUE v;
hash = rb_hash_start(hash);
v = rb_hash(RANGE_BEG(range));
hash = rb_hash_uint(hash, NUM2LONG(v));
v = rb_hash(RANGE_END(range));
hash = rb_hash_uint(hash, NUM2LONG(v));
hash = rb_hash_uint(hash, EXCL(range) << 24);
hash = rb_hash_end(hash);
return ST2FIX(hash);
}
如果 object 是 self 的一个元素,则返回 true,否则返回 false。
(1..4).include?(2) # => true (1..4).include?(5) # => false (1..4).include?(4) # => true (1...4).include?(4) # => false ('a'..'d').include?('b') # => true ('a'..'d').include?('e') # => false ('a'..'d').include?('B') # => false ('a'..'d').include?('d') # => true ('a'...'d').include?('d') # => false
如果起始和结束是数值型的,include? 的行为类似于 cover?
(1..3).include?(1.5) # => true (1..3).cover?(1.5) # => true
但当不是数值型时,这两个方法可能会有所不同
('a'..'d').include?('cc') # => false ('a'..'d').cover?('cc') # => true
相关: Range#cover?.
返回 self 的字符串表示形式,包括 begin.inspect 和 end.inspect
(1..4).inspect # => "1..4" (1...4).inspect # => "1...4" (1..).inspect # => "1.." (..4).inspect # => "..4"
('a'..'d').to_s # => "a..d" ('a'..'d').inspect # => "\"a\"..\"d\""
相关: Range#to_s.
static VALUE
range_inspect(VALUE range)
{
return rb_exec_recursive(inspect_range, range, 0);
}
如果没有参数,则返回 self 的最后一个元素(如果存在)
(1..4).last # => 4 ('a'..'d').last # => "d"
请注意,即使 exclude_end? 为 true,没有参数的 last 也会返回 self 的结束元素
(1...4).last # => 4 ('a'...'d').last # => "d"
如果给定非负整数参数 n,则返回数组中的最后 n 个元素
(1..10).last(3) # => [8, 9, 10] (1..10).last(0) # => [] (1..4).last(50) # => [1, 2, 3, 4]
请注意,如果 exclude_end? 为 true,则带参数的 last 不会返回 self 的结束元素
(1...4).last(3) # => [1, 2, 3] ('a'...'d').last(3) # => ["a", "b", "c"]
如果不存在最后一个元素,则引发异常
(1..).last # Raises RangeError
static VALUE
range_last(int argc, VALUE *argv, VALUE range)
{
VALUE b, e;
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot get the last element of endless range");
}
if (argc == 0) return RANGE_END(range);
b = RANGE_BEG(range);
e = RANGE_END(range);
if (RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e) &&
RB_LIKELY(rb_method_basic_definition_p(rb_cRange, idEach))) {
return rb_int_range_last(argc, argv, range);
}
return rb_ary_last(argc, argv, rb_Array(range));
}
返回 self 中的最大值,使用方法 #<=> 或给定的代码块进行比较。
如果没有给定参数和代码块,则返回 self 的最大值元素。
(1..4).max # => 4 ('a'..'d').max # => "d" (-4..-1).max # => -1
如果给定非负整数参数 n,并且没有给定代码块,则返回数组中 self 的 n 个最大值元素
(1..4).max(2) # => [4, 3] ('a'..'d').max(2) # => ["d", "c"] (-4..-1).max(2) # => [-1, -2] (1..4).max(50) # => [4, 3, 2, 1]
如果给定代码块,则会调用它
-
首先,使用
self的前两个元素。 -
然后,按顺序,使用到目前为止的最大值和
self的下一个元素。
为了说明
(1..4).max {|a, b| p [a, b]; a <=> b } # => 4
输出
[2, 1] [3, 2] [4, 3]
如果没有给定参数和代码块,则返回对代码块的最后一次调用的返回值
(1..4).max {|a, b| -(a <=> b) } # => 1
如果给定非负整数参数 n 和代码块,则返回数组中对代码块的最后 n 次调用的返回值
(1..4).max(2) {|a, b| -(a <=> b) } # => [1, 2] (1..4).max(50) {|a, b| -(a <=> b) } # => [1, 2, 3, 4]
如果 n 为零,则返回一个空数组
(1..4).max(0) # => [] (1..4).max(0) {|a, b| -(a <=> b) } # => []
如果符合以下条件,则返回 nil 或空数组:
-
范围的起始值大于结束值
(4..1).max # => nil (4..1).max(2) # => [] (4..1).max {|a, b| -(a <=> b) } # => nil (4..1).max(2) {|a, b| -(a <=> b) } # => []
-
独占范围的起始值等于结束值
(1...1).max # => nil (1...1).max(2) # => [] (1...1).max {|a, b| -(a <=> b) } # => nil (1...1).max(2) {|a, b| -(a <=> b) } # => []
如果以下任一情况成立,则引发异常:
-
self是一个无结束范围:(1..)。 -
给定了代码块,并且
self是一个无起始范围。
相关: Range#min, Range#minmax.
static VALUE
range_max(int argc, VALUE *argv, VALUE range)
{
VALUE e = RANGE_END(range);
int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot get the maximum of endless range");
}
VALUE b = RANGE_BEG(range);
if (rb_block_given_p() || (EXCL(range) && !nm) || argc) {
if (NIL_P(b)) {
rb_raise(rb_eRangeError, "cannot get the maximum of beginless range with custom comparison method");
}
return rb_call_super(argc, argv);
}
else {
int c = NIL_P(b) ? -1 : OPTIMIZED_CMP(b, e);
if (c > 0)
return Qnil;
if (EXCL(range)) {
if (!RB_INTEGER_TYPE_P(e)) {
rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
}
if (c == 0) return Qnil;
if (!RB_INTEGER_TYPE_P(b)) {
rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
}
if (FIXNUM_P(e)) {
return LONG2NUM(FIX2LONG(e) - 1);
}
return rb_funcall(e, '-', 1, INT2FIX(1));
}
return e;
}
}
如果 object 是 self 的一个元素,则返回 true,否则返回 false。
(1..4).include?(2) # => true (1..4).include?(5) # => false (1..4).include?(4) # => true (1...4).include?(4) # => false ('a'..'d').include?('b') # => true ('a'..'d').include?('e') # => false ('a'..'d').include?('B') # => false ('a'..'d').include?('d') # => true ('a'...'d').include?('d') # => false
如果起始和结束是数值型的,include? 的行为类似于 cover?
(1..3).include?(1.5) # => true (1..3).cover?(1.5) # => true
但当不是数值型时,这两个方法可能会有所不同
('a'..'d').include?('cc') # => false ('a'..'d').cover?('cc') # => true
相关: Range#cover?.
static VALUE
range_include(VALUE range, VALUE val)
{
VALUE ret = range_include_internal(range, val);
if (!UNDEF_P(ret)) return ret;
return rb_call_super(1, &val);
}
返回 self 中的最小值,使用方法 #<=> 或给定的代码块进行比较。
如果没有给定参数和代码块,则返回 self 的最小值元素。
(1..4).min # => 1 ('a'..'d').min # => "a" (-4..-1).min # => -4
如果给定非负整数参数 n,并且没有给定代码块,则返回数组中 self 的 n 个最小值元素
(1..4).min(2) # => [1, 2] ('a'..'d').min(2) # => ["a", "b"] (-4..-1).min(2) # => [-4, -3] (1..4).min(50) # => [1, 2, 3, 4]
如果给定代码块,则会调用它
-
首先,使用
self的前两个元素。 -
然后,按顺序,使用到目前为止的最小值和
self的下一个元素。
为了说明
(1..4).min {|a, b| p [a, b]; a <=> b } # => 1
输出
[2, 1] [3, 1] [4, 1]
如果没有给定参数和代码块,则返回对代码块的最后一次调用的返回值
(1..4).min {|a, b| -(a <=> b) } # => 4
如果给定非负整数参数 n 和代码块,则返回数组中对代码块的最后 n 次调用的返回值
(1..4).min(2) {|a, b| -(a <=> b) } # => [4, 3] (1..4).min(50) {|a, b| -(a <=> b) } # => [4, 3, 2, 1]
如果 n 为零,则返回一个空数组
(1..4).min(0) # => [] (1..4).min(0) {|a, b| -(a <=> b) } # => []
如果符合以下条件,则返回 nil 或空数组:
-
范围的起始值大于结束值
(4..1).min # => nil (4..1).min(2) # => [] (4..1).min {|a, b| -(a <=> b) } # => nil (4..1).min(2) {|a, b| -(a <=> b) } # => []
-
独占范围的起始值等于结束值
(1...1).min # => nil (1...1).min(2) # => [] (1...1).min {|a, b| -(a <=> b) } # => nil (1...1).min(2) {|a, b| -(a <=> b) } # => []
如果以下任一情况成立,则引发异常:
-
self是一个无起始范围:(..4)。 -
给定了代码块,并且
self是一个无结束范围。
相关: Range#max, Range#minmax.
static VALUE
range_min(int argc, VALUE *argv, VALUE range)
{
if (NIL_P(RANGE_BEG(range))) {
rb_raise(rb_eRangeError, "cannot get the minimum of beginless range");
}
if (rb_block_given_p()) {
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot get the minimum of endless range with custom comparison method");
}
return rb_call_super(argc, argv);
}
else if (argc != 0) {
return range_first(argc, argv, range);
}
else {
VALUE b = RANGE_BEG(range);
VALUE e = RANGE_END(range);
int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e);
if (c > 0 || (c == 0 && EXCL(range)))
return Qnil;
return b;
}
}
返回一个包含 self 中最小值和最大值的 2 个元素数组,可以根据比较方法 #<=> 或给定的代码块返回。
如果没有给定代码块,则返回最小值和最大值,使用 #<=> 进行比较
(1..4).minmax # => [1, 4] (1...4).minmax # => [1, 3] ('a'..'d').minmax # => ["a", "d"] (-4..-1).minmax # => [-4, -1]
如果给定了代码块,则代码块必须返回一个整数
-
如果
a小于b,则为负数。 -
如果
a和b相等,则为零。 -
如果
a大于b,则为正数。
调用代码块 self.size 次以比较元素;返回一个包含 self 中最小值和最大值的 2 个元素 Array,根据代码块
(1..4).minmax {|a, b| -(a <=> b) } # => [4, 1]
如果符合以下条件,则返回 [nil, nil]:
-
范围的起始值大于结束值
(4..1).minmax # => [nil, nil] (4..1).minmax {|a, b| -(a <=> b) } # => [nil, nil]
-
独占范围的起始值等于结束值
(1...1).minmax # => [nil, nil] (1...1).minmax {|a, b| -(a <=> b) } # => [nil, nil]
如果 self 是无起始或无结束的范围,则引发异常。
static VALUE
range_minmax(VALUE range)
{
if (rb_block_given_p()) {
return rb_call_super(0, NULL);
}
return rb_assoc_new(
rb_funcall(range, id_min, 0),
rb_funcall(range, id_max, 0)
);
}
如果 range 与 self 重叠,则返回 true,否则返回 false。
(0..2).overlap?(1..3) #=> true (0..2).overlap?(3..4) #=> false (0..).overlap?(..0) #=> true
对于非范围参数,会引发 TypeError。
(1..3).overlap?(1) # TypeError
如果对 #<=> 的内部调用返回 nil,则返回 false;也就是说,操作数不可比较。
(1..3).overlap?('a'..'d') # => false
如果 self 或 range 为空,则返回 false。“空范围”表示其起始值大于或等于(对于独占范围)其结束值。
(4..1).overlap?(2..3) # => false (4..1).overlap?(..3) # => false (4..1).overlap?(2..) # => false (2...2).overlap?(1..2) # => false (1..4).overlap?(3..2) # => false (..4).overlap?(3..2) # => false (1..).overlap?(3..2) # => false (1..2).overlap?(2...2) # => false
如果 self 和 range 其中一个的起始值大于或等于(如果另一个是独占范围),则另一个的结束值,则返回 false
(4..5).overlap?(2..3) # => false (4..5).overlap?(2...4) # => false (1..2).overlap?(3..4) # => false (1...3).overlap?(3..4) # => false
如果 self 和 range 其中一个的结束值大于或等于(对于独占范围),则另一个的结束值,则返回 false
(4..5).overlap?(2..3) # => false (4..5).overlap?(2...4) # => false (1..2).overlap?(3..4) # => false (1...3).overlap?(3..4) # => false
请注意,该方法不会对无起始范围是否实际为空做任何假设,即使其上限是其类型的最小值,因此所有这些都将返回 true
(...-Float::INFINITY).overlap?(...-Float::INFINITY) # => true (..."").overlap?(..."") # => true (...[]).overlap?(...[]) # => true
即使这些范围实际上是空的(没有数字可以小于 -Float::INFINITY),它们仍然被认为与自身重叠。
相关: Range#cover?.
static VALUE
range_overlap(VALUE range, VALUE other)
{
if (!rb_obj_is_kind_of(other, rb_cRange)) {
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Range)",
rb_class_name(rb_obj_class(other)));
}
VALUE self_beg = RANGE_BEG(range);
VALUE self_end = RANGE_END(range);
int self_excl = EXCL(range);
VALUE other_beg = RANGE_BEG(other);
VALUE other_end = RANGE_END(other);
int other_excl = EXCL(other);
if (empty_region_p(self_beg, other_end, other_excl)) return Qfalse;
if (empty_region_p(other_beg, self_end, self_excl)) return Qfalse;
if (!NIL_P(self_beg) && !NIL_P(other_beg)) {
VALUE cmp = rb_funcall(self_beg, id_cmp, 1, other_beg);
if (NIL_P(cmp)) return Qfalse;
/* if both begin values are equal, no more comparisons needed */
if (rb_cmpint(cmp, self_beg, other_beg) == 0) return Qtrue;
}
else if (NIL_P(self_beg) && !NIL_P(self_end) && NIL_P(other_beg)) {
VALUE cmp = rb_funcall(self_end, id_cmp, 1, other_end);
return RBOOL(!NIL_P(cmp));
}
if (empty_region_p(self_beg, self_end, self_excl)) return Qfalse;
if (empty_region_p(other_beg, other_end, other_excl)) return Qfalse;
return Qtrue;
}
如果给定代码块,则以相反的顺序将 self 的每个元素传递给该代码块
a = [] (1..4).reverse_each {|element| a.push(element) } # => 1..4 a # => [4, 3, 2, 1] a = [] (1...4).reverse_each {|element| a.push(element) } # => 1...4 a # => [3, 2, 1]
如果没有给定代码块,则返回一个枚举器。
static VALUE
range_reverse_each(VALUE range)
{
RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_reverse_size);
VALUE beg = RANGE_BEG(range);
VALUE end = RANGE_END(range);
int excl = EXCL(range);
if (NIL_P(end)) {
rb_raise(rb_eTypeError, "can't iterate from %s",
rb_obj_classname(end));
}
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
if (excl) {
if (end == LONG2FIX(FIXNUM_MIN)) return range;
end = rb_int_minus(end, INT2FIX(1));
}
range_reverse_each_fixnum_section(beg, end);
}
else if ((NIL_P(beg) || RB_INTEGER_TYPE_P(beg)) && RB_INTEGER_TYPE_P(end)) {
if (excl) {
end = rb_int_minus(end, INT2FIX(1));
}
range_reverse_each_positive_bignum_section(beg, end);
range_reverse_each_fixnum_section(beg, end);
range_reverse_each_negative_bignum_section(beg, end);
}
else {
return rb_call_super(0, NULL);
}
return range;
}
如果起始值和结束值都是数值型的,则返回 self 中的元素计数;否则返回 nil
(1..4).size # => 4 (1...4).size # => 3 (1..).size # => Infinity ('a'..'z').size # => nil
如果 self 不可迭代,则会引发异常。
(0.5..2.5).size # TypeError (..1).size # TypeError
相关:Range#count。
static VALUE
range_size(VALUE range)
{
VALUE b = RANGE_BEG(range), e = RANGE_END(range);
if (RB_INTEGER_TYPE_P(b)) {
if (rb_obj_is_kind_of(e, rb_cNumeric)) {
return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
}
if (NIL_P(e)) {
return DBL2NUM(HUGE_VAL);
}
}
if (!discrete_object_p(b)) {
CANT_ITERATE_FROM(b);
}
return Qnil;
}
以 s 为步长迭代范围内的元素。迭代通过 + 运算符执行。
(0..6).step(2) { puts _1 } #=> 1..5 # Prints: 0, 2, 4, 6 # Iterate between two dates in step of 1 day (24 hours) (Time.utc(2022, 2, 24)..Time.utc(2022, 3, 1)).step(24*60*60) { puts _1 } # Prints: # 2022-02-24 00:00:00 UTC # 2022-02-25 00:00:00 UTC # 2022-02-26 00:00:00 UTC # 2022-02-27 00:00:00 UTC # 2022-02-28 00:00:00 UTC # 2022-03-01 00:00:00 UTC
如果 + step 减少了值,当步长 begin 高于 end 时,仍然会执行迭代。
(0..6).step(-2) { puts _1 } # Prints nothing (6..0).step(-2) { puts _1 } # Prints: 6, 4, 2, 0 (Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step(-24*60*60) { puts _1 } # Prints: # 2022-03-01 00:00:00 UTC # 2022-02-28 00:00:00 UTC # 2022-02-27 00:00:00 UTC # 2022-02-26 00:00:00 UTC # 2022-02-25 00:00:00 UTC # 2022-02-24 00:00:00 UTC
当未提供代码块,且范围边界和步长为 Numeric 类型时,该方法返回 Enumerator::ArithmeticSequence。
(1..5).step(2) # => ((1..5).step(2)) (1.0..).step(1.5) #=> ((1.0..).step(1.5)) (..3r).step(1/3r) #=> ((..3/1).step((1/3)))
Enumerator::ArithmeticSequence 可以进一步用作迭代或切片集合的值对象(请参见 Array#[])。有一个方便的方法 % ,其行为类似于 step,可以更清晰地生成算术序列。
# Same as (1..5).step(2) (1..5) % 2 # => ((1..5).%(2))
在一般情况下,当未提供代码块时,会返回 Enumerator。
('a'..).step('b') #=> #<Enumerator: "a"..:step("b")> ('a'..).step('b').take(3) #=> ["a", "ab", "abb"]
如果未提供 s,则对于具有数字 begin 的范围,它被视为 1。
(1..5).step { p _1 } # Prints: 1, 2, 3, 4, 5
对于非数字范围,缺少步长是一个错误。
(Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step { p _1 } # raises: step is required for non-numeric ranges (ArgumentError)
出于向后兼容的原因,String 范围支持使用字符串步长和整数步长进行迭代。在后一种情况下,通过使用 String#succ 计算下一个值来执行迭代。
('a'..'e').step(2) { p _1 } # Prints: a, c, e ('a'..'e').step { p _1 } # Default step 1; prints: a, b, c, d, e
static VALUE
range_step(int argc, VALUE *argv, VALUE range)
{
VALUE b, e, v, step;
int c, dir;
b = RANGE_BEG(range);
e = RANGE_END(range);
const VALUE b_num_p = rb_obj_is_kind_of(b, rb_cNumeric);
const VALUE e_num_p = rb_obj_is_kind_of(e, rb_cNumeric);
// For backward compatibility reasons (conforming to behavior before 3.4), String/Symbol
// supports both old behavior ('a'..).step(1) and new behavior ('a'..).step('a')
// Hence the additional conversion/additional checks.
const VALUE str_b = rb_check_string_type(b);
const VALUE sym_b = SYMBOL_P(b) ? rb_sym2str(b) : Qnil;
if (rb_check_arity(argc, 0, 1))
step = argv[0];
else {
if (b_num_p || !NIL_P(str_b) || !NIL_P(sym_b) || (NIL_P(b) && e_num_p))
step = INT2FIX(1);
else
rb_raise(rb_eArgError, "step is required for non-numeric ranges");
}
const VALUE step_num_p = rb_obj_is_kind_of(step, rb_cNumeric);
if (step_num_p && b_num_p && rb_equal(step, INT2FIX(0))) {
rb_raise(rb_eArgError, "step can't be 0");
}
if (!rb_block_given_p()) {
// This code is allowed to create even beginless ArithmeticSequence, which can be useful,
// e.g., for array slicing:
// ary[(..-1) % 3]
if (step_num_p && ((b_num_p && (NIL_P(e) || e_num_p)) || (NIL_P(b) && e_num_p))) {
return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
range_step_size, b, e, step, EXCL(range));
}
// ...but generic Enumerator from beginless range is useless and probably an error.
if (NIL_P(b)) {
rb_raise(rb_eArgError, "#step for non-numeric beginless ranges is meaningless");
}
RETURN_SIZED_ENUMERATOR(range, argc, argv, 0);
}
if (NIL_P(b)) {
rb_raise(rb_eArgError, "#step iteration for beginless ranges is meaningless");
}
if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
/* perform summation of numbers in C until their reach Fixnum limit */
long i = FIX2LONG(b), unit = FIX2LONG(step);
do {
rb_yield(LONG2FIX(i));
i += unit; /* FIXABLE+FIXABLE never overflow */
} while (FIXABLE(i));
b = LONG2NUM(i);
/* then switch to Bignum API */
for (;; b = rb_big_plus(b, step))
rb_yield(b);
}
else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) {
/* fixnums are special: summation is performed in C for performance */
long end = FIX2LONG(e);
long i, unit = FIX2LONG(step);
if (unit < 0) {
if (!EXCL(range))
end -= 1;
i = FIX2LONG(b);
while (i > end) {
rb_yield(LONG2NUM(i));
i += unit;
}
} else {
if (!EXCL(range))
end += 1;
i = FIX2LONG(b);
while (i < end) {
rb_yield(LONG2NUM(i));
i += unit;
}
}
}
else if (b_num_p && step_num_p && ruby_float_step(b, e, step, EXCL(range), TRUE)) {
/* done */
} else if (!NIL_P(str_b) && FIXNUM_P(step)) {
// backwards compatibility behavior for String only, when no step/Integer step is passed
// See discussion in https://bugs.ruby-lang.org/issues/18368
VALUE iter[2] = {INT2FIX(1), step};
if (NIL_P(e)) {
rb_str_upto_endless_each(str_b, step_i, (VALUE)iter);
}
else {
rb_str_upto_each(str_b, e, EXCL(range), step_i, (VALUE)iter);
}
} else if (!NIL_P(sym_b) && FIXNUM_P(step)) {
// same as above: backward compatibility for symbols
VALUE iter[2] = {INT2FIX(1), step};
if (NIL_P(e)) {
rb_str_upto_endless_each(sym_b, sym_step_i, (VALUE)iter);
}
else {
rb_str_upto_each(sym_b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
}
} else {
v = b;
if (!NIL_P(e)) {
if (b_num_p && step_num_p && r_less(step, INT2FIX(0)) < 0) {
// iterate backwards, for consistency with ArithmeticSequence
if (EXCL(range)) {
for (; r_less(e, v) < 0; v = rb_funcall(v, id_plus, 1, step))
rb_yield(v);
}
else {
for (; (c = r_less(e, v)) <= 0; v = rb_funcall(v, id_plus, 1, step)) {
rb_yield(v);
if (!c) break;
}
}
} else {
// Direction of the comparison. We use it as a comparison operator in cycle:
// if begin < end, the cycle performs while value < end (iterating forward)
// if begin > end, the cycle performs while value > end (iterating backward with
// a negative step)
dir = r_less(b, e);
// One preliminary addition to check the step moves iteration in the same direction as
// from begin to end; otherwise, the iteration should be empty.
if (r_less(b, rb_funcall(b, id_plus, 1, step)) == dir) {
if (EXCL(range)) {
for (; r_less(v, e) == dir; v = rb_funcall(v, id_plus, 1, step))
rb_yield(v);
}
else {
for (; (c = r_less(v, e)) == dir || c == 0; v = rb_funcall(v, id_plus, 1, step)) {
rb_yield(v);
if (!c) break;
}
}
}
}
}
else
for (;; v = rb_funcall(v, id_plus, 1, step))
rb_yield(v);
}
return range;
}
返回一个包含 self 中元素的数组(如果是一个有限集合);否则会引发异常。
(1..4).to_a # => [1, 2, 3, 4] (1...4).to_a # => [1, 2, 3] ('a'..'d').to_a # => ["a", "b", "c", "d"]
static VALUE
range_to_a(VALUE range)
{
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot convert endless range to an array");
}
return rb_call_super(0, 0);
}
返回 self 的字符串表示形式,包括 begin.to_s 和 end.to_s。
(1..4).to_s # => "1..4" (1...4).to_s # => "1...4" (1..).to_s # => "1.." (..4).to_s # => "..4"
('a'..'d').to_s # => "a..d" ('a'..'d').inspect # => "\"a\"..\"d\""
相关:Range#inspect。
static VALUE
range_to_s(VALUE range)
{
VALUE str, str2;
str = rb_obj_as_string(RANGE_BEG(range));
str2 = rb_obj_as_string(RANGE_END(range));
str = rb_str_dup(str);
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
rb_str_append(str, str2);
return str;
}