增加初始" Setter" (属性Writer风格)方法调用

时间:2015-04-10 23:43:45

标签: ruby-on-rails ruby

我努力在其他地方找到这个问题的另一个版本,所以如果我错过了某些内容,请道歉......我的代码片段基本上是清单5.7中的简化版本(为清晰起见)(第138页)来自David A. Black的 The Well-Grounded Rubyist(第一版),如果有人熟悉的话。

注意:我知道很少使用类实例变量,但我仍然想要理解这个例子。

作者基本上利用这种设计允许通过子类独立使用实例计数器......如果第一次调用" setter"方法(这里,在" initialize"方法中)是增量,发生了什么,拼写出来?我看到它一定是在调用" getter"方法,因为它的条件赋值按预期运行。没有它,' +'不被认为是一种方法。我只是不知道如何/为什么。发生了什么事?

类似于:@ thing_count = _________ + num

它是否正在调用" getter"空白的方法?是否有其他替代方案可以让它更清晰?

谢谢!

class Thing
  def self.thing_count
    @thing_count ||= 0
  end

  def self.thing_count=(num)
    @thing_count = num
  end

  def initialize
    self.class.thing_count += 1
  end
end

first = Thing.new
second = Thing.new
third = Thing.new

puts Thing.thing_count

#=> 3

2 个答案:

答案 0 :(得分:2)

self.class.thing_count += 1正在调用方法def self.thing_count,即将@thing_count设置为0(如果尚未设置)或+ = 1(将{1}添加到如果先前已设置,则为@thing_count)的当前值。

@thing_count ||= 0称为memoizing,如果尚未将@thing_count定义为任何内容,则将+设置为0(这就是为什么+不会是{{1}}因为它在零上呼叫{{1}}而被认可。)

答案 1 :(得分:1)

这是编写可能更容易理解的类似逻辑的一种方法:

class Thing

  @@count = 0  # The double-at-sign makes this a class variable.

  def initialize
    @@count += 1
    puts "count is now #{@@count}"
  end

end

first = Thing.new
=> count is now 1
second = Thing.new
=> count is now 2
third = Thing.new
=> count is now 3

下一步是在实例外部访问类变量@@count。为此,我们创建了访问器:

def self.count
  @@count
end

def self.count=(num)
  @@count = num
end

现在你可以写:

Thing.count
=> 3

您的代码基本上是同一种想法:

class Thing

  def self.count
    @@count ||= 0
  end

  def self.count=(num)
    @@count = num
  end

  def initialize
    self.class.count += 1
  end

end

当您运行Thing.new时,会发生什么事情:

  1. initialize
  2. 调用返回实例的self
  3. 调用.class,返回Thing类。
  4. 致电.count
  5. 检查@@count变量;如果它存在,则返回它,否则将其设置为0并返回它。
  6. 调用+= 1,这通常是x = x + 1
  7. 的语法糖
  8. @@count变量的值加1(但不影响@@count变量)
  9. 使用新值调用Thing.count=
  10. @@count设为新值。
  11. 代码使用这个Ruby惯用法来设置默认值。通常,对于典型的实例变量,惯用法看起来像这样:

    def foo
      @foo ||= "bar"
    end
    

    对于典型的类变量:

    def self.foo
      @@foo ||= "bar"
    end
    

    这个成语是一种懒惰的设置。在调用方法之前,该变量不存在。每次调用该方法时,它都会检查变量是否已定义(然后返回)或不是(然后设置它)。

    这比设置一次效率低一点。

    在我看来,将类变量显式设置为零一次是更好的编码风格,而不是使用||=懒惰的习语。

    class Demo
      @@foo = "bar"
      ...
    

    如果值为false,那么懒惰的设置习惯用法无法按预期工作:

    def foo
      @foo ||= false  # This will set foo every time
    end
    

    解决方案是检查变量是否已定义:

    def foo
      defined?(@foo) ? @foo : (@foo = false)
    end
    

    另一个Ruby习惯用法是将方法和变量命名为同名。这就是Ruby执行attr_readerattr_writerattr_accessor的方式。

    对于您的代码,请注意您没有任何attr_代码,因此如果您愿意,可以使用您想要的任何变量名称,例如:

    def self.count
      @@whatever ||= 0
    end
    
    def self.count=(num)
      @@whatever = num
    end
    

    这对于信息隐藏目的非常有用。

    评论者allielarson1212提出了一个很好的观点,即成语有时被称为“记忆”。 “备忘录”成语通常更像是这样:

    def foo
      @foo ||= ... a long time-consuming command ...
    end
    

    这是做什么的:

    1. 第一次调用该方法时,运行该命令,然后跟踪结果
    2. 下次调用该方法时,跳过该命令并返回跟踪的结果。