Ruby:Range为空,但使用它进行切片会生成元素

Ruby:Range为空,但使用它进行切片会生成元素,ruby,arrays,range,slice,Ruby,Arrays,Range,Slice,我正在学习Ruby,刚刚学习了一些关于数组和范围的知识。我遇到了一些关于切片的事情,虽然乍一看是有道理的,但当我深入研究时,会有点困惑 表示(2..-1).to_a是一个空数组,表示范围内没有值,对吗? 但是如果我在[:a,:b,:c,:d,:e][2..-1]中使用相同的范围,我将返回[:c,:d,:e],而不是一个空数组 现在,我知道-1代表数组中的最后一个元素,所以它有点道理,被选中的元素就是。但是,如果范围本身是空的,它如何选择任何东西呢?在切片操作中,它并没有将范围视为范围本身,它只是

我正在学习Ruby,刚刚学习了一些关于数组和范围的知识。我遇到了一些关于切片的事情,虽然乍一看是有道理的,但当我深入研究时,会有点困惑

表示
(2..-1).to_a
是一个空数组,表示范围内没有值,对吗?
但是如果我在
[:a,:b,:c,:d,:e][2..-1]
中使用相同的范围,我将返回
[:c,:d,:e]
,而不是一个空数组


现在,我知道-1代表数组中的最后一个元素,所以它有点道理,被选中的元素就是。但是,如果范围本身是空的,它如何选择任何东西呢?

在切片操作中,它并没有将范围视为
范围本身,它只是查看端点的值,在本例中是
2
-1
。由于
-1
具有特殊含义(即列表中的最后一项),因此它只返回从索引
2
处的项到列表末尾的所有内容。在这里,不要把它看作是一个范围,只要把它看作是一种传递两个数字(表示两个端点)的便捷方式即可。

这是一个有趣的问题。答案是,切片阵列时检查的不是范围中的单个元素,而是
第一个
最后一个
元素。具体而言:

>> (2..-1).to_a
=> []
>> (2..-1).first
=> 2
>> (2..-1).last
=> -1
因此,该示例可以工作,因为它将数组从
[2]
元素分割到
[-1]
元素

如果您想要一个一致的方法来考虑这个问题,请考虑<代码>(2…-1)。toAa < /COD>输出在<代码> 2 和<代码> -1 < /代码>之间的整数(其中没有任何代码),但是<<代码>(2…-1)< /代码>意味着从<代码> 2 < /C> >索引到<代码> -1 < /代码>索引>

(来源:Ruby源代码中的
array.c
range.c

还有,复杂的奖励部分:为了得到你所想的意义,你可以使用

>> [:a, :b, :c, :d, :e].values_at *(2..-1).to_a
=> []
Array#[]
方法不使用范围作为范围(也就是说,它不在其上调用
include?
或类似的东西);它只是从中取出两个数字,然后检查它是否是独占的

您可以想象它看起来有点像这样(尽管真正的
[]
是用C实现的,而不是用,当然也处理范围以外的参数):


为了将来的参考,在
*(2..-1).to_a
For中的星是什么?那将是'splat'运算符。更准确地说:
foo([1,2,3])
使用一个(列表)参数调用
foo
foo(*[1,2,3])
用三个参数调用它:它相当于
foo(1,2,3)
;列表被解构,其元素在函数调用上飞溅。
def [](range)
  start = range.begin
  length = range.end - start
  length -= 1 if range.exclude_end?
  slice(start, length)
end