具有相同开头和结尾的Ranges的默认行为是什么?

时间:2014-01-20 16:41:00

标签: ruby

我创建了一个为范围(1...array.length)运行循环的方法。输出始终是正确的,长度大于1,但每当我只有一个字符i.e ['a']的数组时,输出仍然正确。这让我担心的原因是因为我不确定程序如何知道在长度为1的情况下索引nil数组对象... arr[1]

def vowels_in_order?(word)  
  vowels = word.scan(/[aeiou]/)
  (1...vowels.length).each { |index| return false if vowels[index] < vowels[index-1]}
  return true
end 

因此我想知道范围是否存在默认行为,这不会导致循环崩溃。或者可能,它与我的方法有关,因为这也是有洞察力的。

以下是循环技术崩溃的示例:

2.1.0 :1116 > word = "a"
 => "a" 
2.1.0 :1117 > word[1] < word[0]
NoMethodError: undefined method `<' for nil:NilClass
    from (irb#1):1117

5 个答案:

答案 0 :(得分:3)

(1...1)(1...0)都是空的(不包含任何元素),因此调用它们each不会做任何事情。

答案 1 :(得分:2)

根据ruby documentation。有关范围的更详细文档(第一段应该对您有所帮助),请参阅该页面

Ranges constructed using .. run from the start to the end inclusively. 
Those created using ... exclude the end value. 

答案 2 :(得分:2)

让我们前往irb:

irb(main):001:0> (1...1).to_a => []

所以我们有一个空数组

现在让我们来看看你的代码

def vowels_in_order?(word)  
  vowels = word.scan(/[aeiou]/)
  (1...vowels.length).each { |index| return false if vowels[index] < vowels[index-1]}
  return true
end 

这可以重写(对于vowels.length == 1):

def vowels_in_order?(word)  
  vowels = word.scan(/[aeiou]/)
  [].each { |index| return false if vowels[index] < vowels[index-1]}
  return true
end 

您现在可以看到正在迭代一个空数组。因此,{ |index| return false if vowels[index] < vowels[index-1]}块中的代码永远不会运行。我们可以用

测试一下

irb(main):027:0> [].each { |i| puts "hello"} => []

已编辑:未发现您使用的是...而非..

答案 3 :(得分:1)

使用Ranges时需要考虑以下事项。

这些是合理的范围声明:

(1 .. 1).to_a   # => [1]
(1 .. 2).to_a   # => [1, 2]
(1 ... 2).to_a  # => [1]

请注意,1 .. 1相当于1 ... 2

这些不是合理的范围声明,但结果相同:

(1 .. 0).to_a   # => []
(1 ... 1).to_a  # => []

而且,在这两种情况下,Ruby都不会做任何事情,因为范围必须以小于或等于结束值的起始值开始。

来自the Range documentation

  

范围表示间隔 - 一组带有开头和结尾的值。范围可以使用s..e和s ... e literals构建,或者使用:: new构建。使用..构建的范围包括从开始到结束。使用...创建的那些排除了最终值。当用作迭代器时,范围将返回序列中的每个值。

......和......

  

... 将范围视为序列的方法(#each和从Enumerable继承的方法)期望begin对象实现succ方法以按顺序返回下一个对象。

1.succ # => 2会立即导致范围内的迭代退出。

使用..而不是...。由于...的行为等效行为1 ... 2(1) .. (2 - 1)是许多错误和维护问题的根源。人们的目光很快就能看到和识别何时使用...代替.. IF 你坚持使用...,然后格式化你的代码以获取合法性,并使用空格给眼睛一些东西。

1 .. 1

比以下内容更具可读性:

1..1

或:

1...2

答案 4 :(得分:-1)

我假设您对创建范围的语法a...b实际上做了什么有一些误解。请查看range,其中解释了此语法。

定义:

  

范围表示间隔 - 一组带有开头和结尾的值。范围可以使用s..e和s ... e literals构建,或者使用:: new构建。使用..构建的范围包括从开始到结束。使用...创建的那些排除了最终值。当用作迭代器时,范围将返回序列中的每个值。

实施例

(-1..-5).to_a      #=> []
(-5..-1).to_a      #=> [-5, -4, -3, -2, -1]
('a'..'e').to_a    #=> ["a", "b", "c", "d", "e"]
('a'...'e').to_a   #=> ["a", "b", "c", "d"]