200

https://stackoverflow.com/questions/826734/when-do-ruby-instance-variables-get-setを読みましたが、いつクラスのインスタンス変数を使用するかについて 2 つの考えがあります。

クラス変数はクラスのすべてのオブジェクトで共有され、インスタンス変数は 1 つのオブジェクトに属します。クラス変数がある場合、クラス インスタンス変数を使用する余地はあまりありません。

誰かがこれら2つの違いとそれらをいつ使用するかを説明できますか?

コード例を次に示します。

class S
  @@k = 23
  @s = 15
  def self.s
    @s
  end
  def self.k
     @@k
  end

end
p S.s #15
p S.k #23

更新:今わかりました!クラス インスタンス変数は、継承チェーンに沿って渡されません。

4

8 に答える 8

38

ソース

インスタンス メソッドの可用性

  • クラス インスタンス変数は、クラス メソッドでのみ使用でき、インスタンス メソッドでは使用できません。
  • クラス変数は、インスタンス メソッドとクラス メソッドの両方で使用できます。

遺伝性

  • クラス インスタンス変数は、継承チェーンで失われます。
  • クラス変数はそうではありません。
class Vars

  @class_ins_var = "class instance variable value"  #class instance variable
  @@class_var = "class variable value" #class  variable

  def self.class_method
    puts @class_ins_var
    puts @@class_var
  end

  def instance_method
    puts @class_ins_var
    puts @@class_var
  end
end

Vars.class_method

puts "see the difference"

obj = Vars.new

obj.instance_method

class VarsChild < Vars


end

VarsChild.class_method
于 2014-06-08T10:44:08.707 に答える
15

他の人が言ったように、クラス変数は特定のクラスとそのサブクラスの間で共有されます。クラス インスタンス変数は、厳密に 1 つのクラスに属します。そのサブクラスは分離されています。

なぜこの動作が存在するのですか? Ruby ではすべてがオブジェクトであり、クラスも含まれます。つまり、各クラスには、それに対応するクラスClass(というよりは、のサブクラスClass) のオブジェクトがあります。(あなたが言うときclass Foo、あなたは実際には定数Fooを宣言し、それにクラス オブジェクトを代入しています。) そして、すべての Ruby オブジェクトはインスタンス変数を持つことができるので、クラス オブジェクトもインスタンス変数を持つことができます。

問題は、クラス オブジェクトのインスタンス変数が、クラス変数の通常の動作とは異なる動作をすることです。通常、スーパークラスで定義されたクラス変数をそのサブクラスと共有する必要がありますが、インスタンス変数はそうではありません。サブクラスには独自のクラス オブジェクトがあり、そのクラス オブジェクトには独自のインスタンス変数があります。そのため、彼らは、あなたが望む可能性が高い動作を備えた個別のクラス変数を導入しました。

言い換えれば、クラスのインスタンス変数は、Ruby の設計上の偶然のようなものです。それらが探しているものであることが明確にわかっていない限り、おそらくそれらを使用しないでください。

于 2015-02-01T15:07:23.703 に答える
5

Ruby 公式 FAQ: クラス変数とクラス インスタンス変数の違いは何ですか?

主な違いは継承に関する動作です。クラス変数はクラスとそのすべてのサブクラス間で共有されますが、クラス インスタンス変数は 1 つの特定のクラスにのみ属します。

クラス変数は、ある意味で、継承階層のコンテキスト内でグローバル変数と見なすことができ、グローバル変数に伴うすべての問題があります。たとえば、クラス変数が (誤って) そのサブクラスのいずれかによって再割り当てされ、他のすべてのクラスに影響を与える可能性があります。

class Woof

  @@sound = "woof"

  def self.sound
    @@sound
  end
end

Woof.sound  # => "woof"

class LoudWoof < Woof
  @@sound = "WOOF"
end

LoudWoof.sound  # => "WOOF"
Woof.sound      # => "WOOF" (!)

または、祖先クラスが後で再度開かれて変更され、驚くべき結果が生じる可能性があります。

class Foo

  @@var = "foo"

  def self.var
    @@var
  end
end

Foo.var  # => "foo" (as expected)

class Object
  @@var = "object"
end

Foo.var  # => "object" (!)

したがって、自分が何をしているのかを正確に把握していて、この種の動作が明示的に必要な場合を除き、クラス インスタンス変数を使用することをお勧めします。

于 2019-07-30T18:06:21.000 に答える
5

クラス変数を利用するとすぐに便利に思えるかもしれませんが、クラス変数はサブクラス間で共有され、シングルトン メソッドとインスタンス メソッドの両方で参照できるため、重大な欠点があります。それらは共有されているため、サブクラスはクラス変数の値を変更でき、基本クラスも変更の影響を受けます。これは通常、望ましくない動作です。

class C
  @@c = 'c'
  def self.c_val
    @@c
  end
end

C.c_val
 => "c" 

class D < C
end

D.instance_eval do 
  def change_c_val
    @@c = 'd'
  end
end
 => :change_c_val 

D.change_c_val
(irb):12: warning: class variable access from toplevel
 => "d" 

C.c_val
 => "d" 

Rails には、class_attribute という便利なメソッドが導入されています。名前が示すように、値がサブクラスによって継承可能なクラス レベルの属性を宣言します。class_attribute 値は、クラス変数の場合と同様に、シングルトン メソッドとインスタンス メソッドの両方でアクセスできます。ただし、Rails の class_attribute の大きな利点は、サブクラスが独自の値を変更でき、親クラスに影響を与えないことです。

class C
  class_attribute :c
  self.c = 'c'
end

 C.c
 => "c" 

class D < C
end

D.c = 'd'
 => "d" 

 C.c
 => "c" 
于 2019-04-02T04:16:13.303 に答える