【问题标题】:'undefined method `>' for nil:NilClass in ruby'undefined method `>' for nil:NilClass in ruby
【发布时间】:2017-02-14 18:38:55
【问题描述】:

这是我将用户输入的字符串转换为凯撒密码的代码。

puts "text?"
text = gets.chomp

puts "key?"
key = gets.chomp.to_i 

plainTex = Array.new 
ciphTex = Array.new

j = 0 

text.each_byte do |i|
  plainTex[j] = i
  j += 1
end

j = 0 

plainTex.each_entry do |i|

  if ( i == 32 )
    ciphTex[j] = plainTex[j]
    j += 1
    end

  if( plainTex[j] > 64) and (plainTex[j] < 91 )
    if( (plainTex[j] + key) > 91)
      ciphTex[j] = (plainTex[j] + key ) - 90
      j += 1
    else 
      ciphTex[j] = plainTex[j] + key 
      j += 1 
    end
  end

  if( plainTex[j] > 94) and (plainTex[j] < 123)
    if( (plainTex [j] + key) > 122)
      ciphTex [j] = (plainTex[j] + key) - 122
      j += 1 
    else 
      ciphTex[j] = plainTex[j] + key
      j += 1
    end
  end
 end 

ciphTex.each_entry do |i|
  puts i
end

现在,我遇到了错误: nil:NilClass (NoMethodError) 的未定义方法`>'

在网络上搜索让我得出结论,plainTex 可能是 nil,正如错误消息所说(这不应该是这种情况,因为 plainTex 是预先提供数据的)。

附带说明:当输入字符串全部为小写且没有空格时,程序运行良好。我不知道为什么。

那么,我做错了什么?

【问题讨论】:

  • 好的起点是记下错误中的行号,这将有助于缩小范围。
  • 第 26 行:if(plainTex[j] > 64) 和 (plainTex[j]
  • 您调用的对象&gt;nil。你在什么对象上调用&gt;?提示:它不是 plainTex
  • 这不是plaintexj'th 元素吗?因为有plainTex[j] &gt; 64的比较
  • @arun-that-plays-chess plaintex[j] 可能为零。调试器可能会有所帮助

标签: ruby


【解决方案1】:

问题说明

当您访问索引超出范围的数组时,您不会收到错误,但结果为nil

irb --simple-prompt
>> a = [1]
=> [1]
>> a[0]
=> 1
>> a[1]
=> nil
>> a[200]
=> nil

调试代码

一些 puts 语句揭示了这个问题:

text.each_byte do |i|
  plainTex[j] = i
  j += 1
end

j = 0 

puts "Length: #{plainTex.length}"

plainTex.each_entry do |i|

  if ( i == 32 )
    ciphTex[j] = plainTex[j]
    j += 1
  end
  puts "j: #{j}"

这是输出

text?
Testing Test
key?
32
Length: 12
j: 0
j: 2
j: 3
j: 4
j: 5
j: 6
j: 7
j: 8
j: 10
j: 11
j: 12
test.rb:30:in `block in <main>': undefined method `>' for nil:NilClass (NoMethodError)
    from test.rb:23:in `each'
    from test.rb:23:in `each_entry'
    from test.rb:23:in `<main>

本例中数组的最后一个索引是 11,而您访问的是索引 12。 你得到了结果 nil 然后你尝试在 nil 上调用方法 &gt;

专业调试

您可以安装 gem pry-byebug 并使用短别名 sn 进行步入、下一步等。

https://github.com/deivid-rodriguez/pry-byebug

发现错误

使用pry-byebug 可以立即清楚什么是错误,即使我并不真正理解您的代码,因为这些数字对我来说毫无意义。

对于第一个字母,它在第二个条件 if( plainTex[j] &gt; 64) and (plainTex[j] &lt; 91 ) 中递增 j。然后随着 j 的增加,它移动到 if( plainTex[j] &gt; 94) and (plainTex[j] &lt; 123) 并再次增加它。

您应该使用elsif 来表示所有这些或next

代码清理

Ruby 约定是使用蛇形大小写来命名您的变量,我会更改这段代码:

if( plainTex[j] > 64) and (plainTex[j] < 91 )
  if( (plainTex[j] + key) > 91)
    ciphTex[j] = (plainTex[j] + key ) - 90
    j += 1
  else 
    ciphTex[j] = plainTex[j] + key 
    j += 1 
  end
end

到这里:

if plain_text[j].between?(65, 90)
  ciph_text[j] = plain_text[j] + key
  ciph_text[j] -= 90 if ciph_text[j] > 91
  j += 1
end

您似乎在每个条件下都在重复 j += 1,那么为什么不将其删除到 if/else 块之外并将其作为循环之前的最后一行 end

另外我是人,我不想记住“A”是 65,“Z”是 90。为什么不在代码中这样说呢?

if plain_text[j].between?("A".ord, "Z".ord)

我从未在 ruby​​ 中弄乱过 ASCII,但我相信您可以进一步改进这一点,可能在一个简单的循环中用 10 行或更少的代码完成整个密码。

Ruby 非常擅长处理数组,所以使用它。我会做这样的事情:

plain_text = text.codepoints
cyph_text = plain_text.map do |code|
  if code == ' '.ord
    ' '.ord
  elsif
    # return cypher code
  end
end

查看地图功能的工作原理。

【讨论】:

  • 嗯..但是为什么j的值是从0迭代到2呢?迭代语句明确指出j += 1plainTex[j] 为零的全部原因就是因为这个。我似乎无法理解。
  • 为什么不用require 'pry-byebug' 开始这个文件,然后在循环中放入binding.pry 行,然后按s (或完整的单词step如果你不设置别名?
  • 这些数字是 ASCII 码。如果j 在两个if 条件下都增加了,为什么循环的下一次迭代不会发生呢?但是,是的,我应该使用调试器。我只是认为错误是微不足道的。是的,代码对你来说可能是一团糟,但这并不意味着我不知道如何提问。可以?还是谢谢。
  • 你确实提出了一个很好的问题,我昨天或之前已经投了赞成票。我还提供了一些关于如何清理代码的建议
  • @arun-that-plays-chess - 我提供了一些关于如何改进代码的建议。以自己的方式做这件事很好,尤其是在您刚学习新语言时。
猜你喜欢
  • 2012-08-08
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-18
  • 2015-01-29
  • 1970-01-01
  • 2022-11-14
相关资源
最近更新 更多