【问题标题】:Class variables in RubyRuby 中的类变量
【发布时间】:2012-05-22 14:14:32
【问题描述】:

我从this tutorial 看到了以下示例:

class Song
  @@plays = 0

  def initialize(name, artist, duration)
    @name = name
    @artist = artist
    @duration = duration
    @plays = 0
  end

  def play
    @plays += 1
    @@plays += 1
    "This song: #@plays plays. Total #@@plays plays."
  end
end

s1 = Song.new("Song1", "Artist1", 234)    # test songs
s2 = Song.new("Song2", "Artist2", 345)   

puts s1.play
puts s2.play
puts s1.play
puts s1.play 

@@plays 是否只能在 Song 类中礼貌地访问? This commentary 提出了不推荐使用类变量的观点。是不是 b/c 它们在日常使用中通常不需要,并且在使用时会产生很多调试问题?

【问题讨论】:

    标签: ruby class-variables


    【解决方案1】:

    类变量从来都不是真正需要的。但原因不是它们是共享状态。我的意思是,尽可能避免共享状态是件好事,但这并不是真正的问题。

    不推荐使用它们的原因是,如那篇文章所示,它们确实令人困惑。特别是,一个类的类变量由它的子类和它的子类的实例共享。例如:

    class Parent
    end
    
    class Child1 < Parent
      @@class_var = "Child1's"
    end
    
    class Child2 < Parent
      @@class_var = "Child2's"
    end
    

    使用此代码,Child1 及其实例都将看到一个名为 @@class_var 的类变量,其值为 "Child1's",而 Child2 及其实例都将看到一个名为 @@class_var 的类变量,其值为 "Child2's"。但假设稍后我们重新打开 Parent 并写下:

    class Parent
      @@class_var = "Parent's"
    end
    

    现在 Parent 及其创建的实例都将看到一个名为 @@class_var 的类变量,其值为 "Parent's"但这还不是全部。现在父类有了这个变量,Child1 和 Child2 突然共享这个变量,所以所有的@@class_vars 都有"Parent's" 的值。如果您重新分配 Child1 中的变量,它仍然是共享的,因此所有类都会更新。多么令人困惑!

    你可以使用类的实例变量来代替类变量,像这样:

    class Parent
      @class_var = "Parent's"
      def self.class_var
        @class_var
      end
    end
    
    class Child1 < Parent
      @class_var = "Child1's"
    end
    
    class Child2 < Parent
      @class_var = "Child2's"
    end
    

    现在,Parent.class_var 将返回“Parent's”,Child1.class_var 将返回“Child1's”,Child2.class_var 将返回“Child2's”——正如您所期望的那样。

    【讨论】:

    • 同意这东西真的很混乱,这是一个很好的解释
    【解决方案2】:

    类变量是在类的所有实例之间共享的变量。这意味着从此类实例化的所有对象仅存在一个变量值。这意味着,如果一个对象实例更改了变量的值,那么对于所有其他对象实例,该新值本质上也会发生变化。考虑类变量的另一种思考方式是在单个类的上下文中作为全局变量。

    @@plays #is a class variable
    @plays  #is an instance variable
    $plays  #is a global variable accessed outside a class
    

    因此,在您的示例中,您创建了一个类变量 @@plays 来计算所有歌曲播放的歌曲总数。由于它是类变量,因此不能单独在类外访问。如果您想访问总播放次数,可以使用全局变量。它们以美元符号 $plays 开头(在您的情况下)。我警告你,你应该远离使用全局变量,因为它们有很多问题。您可能会考虑的一件事是创建一个将所有歌曲实例推送到数组中的方法。然后,您可以通过迭代器对所有歌曲的所有播放进行求和。更安全,更不容易出现程序员错误。

    编辑: 这就是为什么全局变量不好的原因

    Are global variables bad?

    【讨论】:

      【解决方案3】:

      @@ 变量将是一个类变量。这通常是不好的做法。在您的代码中它是多余的,因为@plays == @@plays(除非您在代码中的其他位置设置@@plays(不好的做法))

      实际上,现在我看它,它们并不完全一样。 @plays 会记录一首歌曲的播放次数,@@plays 会记录所有歌曲的数量。尽管如此,使用@@plays 可能是不好的做法。通常,你会有一个像“Player”这样的父类来管理所有的歌曲。在“Player”类中应该有一个名为@total_plays 的实例变量。

      【讨论】:

      • 那么@plays 和@@plays 在这种情况下是完全一样的吗?我理解为什么将您所说的内容与文章联系起来是一种不好的做法。
      • 这是错误的@@ 是类变量,不是全局变量。 @plays@@plays 相同。您也根本没有详细说明为什么这可能是一种不好的做法。
      • 我同意。看看我下面的回答
      • 你说得对,安德鲁。我用错了词。它是一个类变量,但通常仍然是个坏主意。
      • 提问者想知道他是否可以在类外访问变量。
      猜你喜欢
      • 2013-04-29
      • 2011-01-06
      • 2013-11-26
      • 2013-03-24
      • 2015-02-28
      • 1970-01-01
      • 2015-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多