首页 > 解决方案 > Ruby 中的实例变量;为什么我必须(有时)指定`self`?

问题描述

为什么 increment_v1 和_v3 工作,但 increment_v2 和 _v4 不工作(v2 返回正确的值,但不改变@counter,v4 失败,“NoMethodError(未定义的方法 `+' for 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_accessorattr_readerand替换它有同样的错误attr_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. 到底是怎么回事?

标签: ruby

解决方案


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

除非您有同名的局部变量,否则getter 方法不需要 self 。设置方法是不同的。您总是需要将 self 与 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

还有很多其他的写法。


推荐阅读