7

我正在学习 Ruby,并且刚刚了解了一些关于数组和范围的内容。我遇到了一些关于切片的东西,虽然乍一看它是有道理的,但当我深入研究它时,我有点困惑。

IRB说这(2..-1).to_a是一个空数组,这意味着该范围内没有值,对吧?
但是如果我在 中使用相同的范围[:a, :b, :c, :d, :e][2..-1],我会返回[:c, :d, :e]而不是一个空数组。

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

4

3 回答 3

11

这是一个有趣的问题。答案是在对数组进行切片时检查的不是范围的各个元素,而是firstandlast元素。具体来说:

>> (2..-1).to_a
=> []
>> (2..-1).first
=> 2
>> (2..-1).last
=> -1

因此,该示例有效,因为它将数组从[2]元素切片到[-1]元素。

如果您想要一种一致的方式来考虑这一点,请考虑(2..-1).to_a输出在2and之间找到的整数-1(其中没有整数),但这[2..-1]意味着从2 index-1 index

(来源:在 Ruby 源代码中。array.crange.c

而且,复杂的奖励部分:要获得您正在考虑的含义,您可以使用

>> [:a, :b, :c, :d, :e].values_at *(2..-1).to_a
=> []
于 2010-10-01T09:06:30.197 回答
3

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

于 2010-10-01T09:06:25.693 回答
1

Array#[]方法不使用范围作为范围(也就是说,它不调用include?它或类似的东西);它只是从中取出两个数字并检查它是否是独占的。

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

def [](range)
  start = range.begin
  length = range.end - start
  length -= 1 if range.exclude_end?
  slice(start, length)
end
于 2010-10-01T09:07:34.640 回答