Ruby中的实例变量;为什么我必须(有时)指定“ self”?

时间:2019-07-27 21:34:19

标签: ruby

为什么increment_v1和_v3起作用,但是increment_v2和_v4不能起作用(v2返回正确的值,但是不改变@counter,v4失败,并显示“ NoMethodError(nil:NilClass的未定义方法'+' )“)

class MyClass
  attr_accessor :counter

  def initialize
    @counter = 0
  end

  def increment_v1
    @counter = counter + 1
  end

  def increment_v2
    counter = @counter + 1
  end

  def increment_v3
    @counter += 1
  end

  def increment_v4
    counter += 1
  end
end

我希望所有这些方法都具有相同的结果(增加@counter值并返回增加的数字)。如果我将attr_accessor替换为attr_readerattr_writer,则会出现相同的错误。我觉得我可能对attr_*方法有误解。

这是控制台中的样子:

2.6.3 :026 > a = MyClass.new
 => #<MyClass:0x00000000018d7240 @counter=0>
2.6.3 :027 > a.increment_v1
 => 1
2.6.3 :028 > a
 => #<MyClass:0x00000000018d7240 @counter=1>
2.6.3 :029 > a.increment_v2
 => 2
2.6.3 :030 > a
 => #<MyClass:0x00000000018d7240 @counter=1>
2.6.3 :031 > a.increment_v3
 => 2
2.6.3 :032 > a
 => #<MyClass:0x00000000018d7240 @counter=2>
2.6.3 :033 > a.increment_v4
Traceback (most recent call last):
        5: from /home/guin/.rvm/rubies/ruby-2.6.3/bin/irb:23:in `<main>'
        4: from /home/guin/.rvm/rubies/ruby-2.6.3/bin/irb:23:in `load'
        3: from /home/guin/.rvm/rubies/ruby-2.6.3/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        2: from (irb):33
        1: from (irb):23:in `increment_v4'
NoMethodError (undefined method `+' for nil:NilClass)

从班级外部运行a.counter += 1可以正常工作。我上课时是否必须指定self.counter += 1?为什么?如果使用self.counter = counter + 1,它甚至可以工作。发生了什么事?

1 个答案:

答案 0 :(得分:3)

如所示,您始终可以使用实例变量(@counter)直接访问属性。但是,您的问题与attr_accessor生成的getter / setter方法有关。

除非您有同名的局部变量,否则getter方法不需要自身 。设置器方法不同。您总是需要将自己与setter一起使用。

例如:

def test_method
  # directly set instance var. this will always work
  @counter = 1  

  # define local variable with same name.
  # this does not call the setter because you don't use self
  counter = 0 

  puts counter
  # prints 0
  # The getter method is never called because you have a local variable
  # with the same name.

  puts self.counter
  # prints 1
  # you can force the getter to be called by using self
end

我认为编写方法的惯用方式是:

def increment_v5
  self.counter += 1
end

但是您也可以这样写:

def increment_v6
  self.counter = counter + 1
  #                \ calls getter
end

还有许多其他编写方法。