我正在学习 Ruby,并且刚刚了解了一些关于数组和范围的内容。我遇到了一些关于切片的东西,虽然乍一看它是有道理的,但当我深入研究它时,我有点困惑。
IRB说这(2..-1).to_a
是一个空数组,这意味着该范围内没有值,对吧?
但是如果我在 中使用相同的范围[:a, :b, :c, :d, :e][2..-1]
,我会返回[:c, :d, :e]
而不是一个空数组。
现在,我知道 -1 代表数组的最后一个元素,所以选择什么是有道理的。但是如果范围本身是空的,它如何选择任何东西?
这是一个有趣的问题。答案是在对数组进行切片时检查的不是范围的各个元素,而是first
andlast
元素。具体来说:
>> (2..-1).to_a
=> []
>> (2..-1).first
=> 2
>> (2..-1).last
=> -1
因此,该示例有效,因为它将数组从[2]
元素切片到[-1]
元素。
如果您想要一种一致的方式来考虑这一点,请考虑(2..-1).to_a
输出在2
and之间找到的整数-1
(其中没有整数),但这[2..-1]
意味着从2
index到-1
index。
(来源:在 Ruby 源代码中。array.c
)range.c
而且,复杂的奖励部分:要获得您正在考虑的含义,您可以使用
>> [:a, :b, :c, :d, :e].values_at *(2..-1).to_a
=> []
在切片操作中,它Range
本身并没有看到范围,它只是查看端点的值,在这种情况下2
和-1
. 由于-1
具有特殊含义(即列表中的最后一项),它只返回从索引项2
到列表末尾的所有内容。不要把它当成Range
这里,只要把它当成传入两个数字(表示两个端点)的便捷方式。
该Array#[]
方法不使用范围作为范围(也就是说,它不调用include?
它或类似的东西);它只是从中取出两个数字并检查它是否是独占的。
你可以想象它看起来有点像这样(尽管 real[]
是在 C 中实现的,而不是在Ruby中,当然也处理范围以外的参数):
def [](range)
start = range.begin
length = range.end - start
length -= 1 if range.exclude_end?
slice(start, length)
end