1

我从本教程中遇到了以下示例:

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 类中礼貌地访问?该评论提出了不建议使用类变量的观点。是 b/c 它们在日常使用中通常不需要,并且在使用时会产生很多调试问题?

4

3 回答 3

18

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

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

class Parent
end

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

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

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

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

现在 Parent 和它创建的实例都将看到一个名为@@class_varvalue的类变量"Parent's"但这还不是全部。现在父类有了这个变量, Child1 和 Child2 突然共享这个变量,所以所有的@@class_vars 都有 value "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”——正如您所期望的那样。

于 2012-05-16T08:02:45.200 回答
1

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

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

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

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

全局变量不好吗?

于 2012-05-15T05:52:56.550 回答
-3

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

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

于 2012-05-15T05:39:29.583 回答