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値で名前が付けられたクラス変数"Child1's"を認識し、Child2 とそのインスタンスはすべて値で名前が付けられたクラス変数を認識し@@class_varます"Child2's"。しかし、後で Parent を再度開いて、次のように記述したとします。

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

これで、親とそれが作成するインスタンスはすべて@@class_var、値で名前が付けられたクラス変数を認識します"Parent's"しかしそれだけではありません。親クラスがこの変数を持つようになったので、Child1 と Child2 が突然変数を共有するため、すべての@@class_varが 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's"Child2.class_varを返します — ご想像のとおりです。

于 2012-05-16T08:02:45.200 に答える
1

クラス変数は、クラスのすべてのインスタンス間で共有される変数です。これは、このクラスからインスタンス化されたすべてのオブジェクトに対して、1 つの変数値のみが存在することを意味します。これは、1 つのオブジェクト インスタンスが変数の値を変更すると、その新しい値が他のすべてのオブジェクト インスタンスに対して本質的に変更されることを意味します。クラス変数のもう 1 つの考え方は、単一のクラスのコンテキスト内のグローバル変数です。

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

したがって、あなたの例では、クラス変数 @@plays を作成して、すべての曲で再生された曲の総数を計算しました。クラス変数なので、クラス外だけではアクセスできません。総再生回数にアクセスしたい場合は、グローバル変数を使用できます。それらはドル記号 $plays (あなたの場合) で始まります。グローバル変数はさまざまな理由で問題があるため、使用しないでください。考えられることの 1 つは、すべての曲のインスタンスを配列にプッシュするメソッドを作成することです。次に、イテレータを使用して、すべての曲のすべての再生を合計できます。安全性が向上し、プログラマーのエラーが発生しにくくなります。

編集:グローバル変数が悪い理由は次のとおりです

グローバル変数は悪いですか?

于 2012-05-15T05:52:56.550 に答える
-3

@@ 変数はクラス変数になります。これは一般的に悪い習慣です。@plays == @@plays であるため、コードでは冗長です(コードの他の場所で @@plays を設定しない限り(悪い習慣))

実際に見てみると、まったく同じではありません。@plays は個々の曲が再生された回数を保持し、@@plays はすべての曲のカウントを保持します。それでも、@@plays を使用するのはおそらく悪い習慣です。通常、すべての曲を管理する「Player」のような親クラスがあります。「Player」クラスには @total_plays というインスタンス変数が必要です。

于 2012-05-15T05:39:29.583 に答える