2

对于以下代码块,我收到“NoMethodError: undefined method `%' for nil:NilClass”:

class Timer
    attr_accessor :seconds

    def initialize
        @seconds = 0
    end

    def time_string

        if seconds < 10
            return "00:00:0" + seconds.to_s
        elsif seconds < 60
            return "00:00:" + seconds.to_s
        elsif seconds < 540
            minutes = seconds / 60
            seconds %= 60
            #seconds = seconds - (minutes * 60)
            return "00:0" + minutes.to_s + ":0" + seconds.to_s
        end
    end

    def timer
        @timer          
    end
end

我知道 'seconds' 是一个 Fixnum,因为当我尝试在没有 #to_s 的情况下 #puts seconds 时出现 NoMethod: Fixnum 错误。此外,前一行中“秒”上的“/”操作也可以正常工作。那么为什么我会收到 NoMethod:nilclass 错误消息?

为什么我什至会收到错误消息?“%”不应该在“/”的任何地方工作吗?

以下代码有效:

        if seconds < 10
            return "00:00:0" + seconds.to_s
        elsif seconds < 60
            return "00:00:" + seconds.to_s
        elsif seconds < 540
            minutes = @seconds / 60
            seconds = @seconds % 60
            return "00:0" + minutes.to_s + ":0" + seconds.to_s
        end

它与实例变量有关,我不理解实例变量。很想知道零是如何进入那里的。

4

2 回答 2

2

我对此不是 100% 确定,但我相信这是一个优先问题。

由于运算符始终优先于方法,因此在评估getter 方法%= 2之前先评估 。我相信seconds这就是导致 的原因。NoMethodError

这也可以解释为什么 using@seconds有效,因为您直接引用实例变量而不是使用在attr_accessor幕后创建的 getter 方法。

作为旁注,我认为从类设计的角度来看,在这种情况下使用实例变量更有意义。

编辑:我上面所说的不可能是正确的,因为这样的方法有效:

class Book
  attr_accessor :title, :length

  def midpoint
    length / 2
  end
end

我认为实际上要简单得多。我假设它的工作方式与写作中的%=其他赋值运算符相同。+=seconds %= 60seconds = seconds % 60

那么可能发生的事情是,由于您正在为 分配一些东西seconds,ruby 将其解释为一个名为 的新局部变量seconds。当%=被“扩展”为seconds = seconds % 60时,seconds右侧的 被解释为同一个局部变量,当前为nil。因此,NoMethodError.

于 2014-08-28T01:51:00.013 回答
2

self这是调用 on 的方法、局部变量和 Ruby 在这些事物之间缺乏语法区别之间的交互。

如果将行更改为:

         self.seconds %= 60

然后它工作正常。

问题在于,当 Ruby 看到对非限定名称的赋值时,它会使用该名称创建一个局部变量,而不是寻找访问器。

这是一个简单的演示:

irb(main):001:0> def foo=(n)
irb(main):002:1>  puts "Calling foo!"
irb(main):003:1>  @foo=n
irb(main):004:1> end    #=> nil
irb(main):005:0> foo=1    #=> 1
irb(main):006:0> @foo    #=> nil
irb(main):007:0> self.foo=2
Calling foo!
=> 2
irb(main):008:0> @foo    #=> 2
于 2014-08-28T02:37:39.867 回答