1

以下のコードのスーパークラスを考えると、すべてのサブクラスにいくつかのインスタンス変数が必要です。

以下のコードはそれを行いますが、考えられるすべてのサブクラスに対してその変数を適切に初期化できません。

スーパークラスの固有クラスを開きました。これがコードです(これもruby​​fiddleにあります):

class SomeSuperClass
  class << self
    attr_accessor :variable
    @variable = ': )' # This does't seem to have any effect
  end
  self.variable = 'This only works for the superclass'
end

class SubClass < SomeSuperClass; end

puts SomeSuperClass.variable # => 'This only works for the superclass'
puts SubClass.variable # => ''

SomeSuperClass.variable = 'I am the superclass'
SubClass.variable = 'I am the subclass'

puts SomeSuperClass.variable # => 'I am the superclass'
puts SubClass.variable # => 'I am the subclass'

可能なすべてのサブクラスを初期化したいと思います。最初の 2 つのプットでは、のみSomeSuperClass.variableが初期化されます。考えられるすべてのサブクラスに対してこの変数を初期化する方法がわかりません。何か案は?

私が見つけた最善の解決策は、次のように、アクセサーをオーバーライドして変数を遅延初期化することです。

class SomeSuperClass
  def self.variable
    @variable ||= 'Hi'
  end
end

動機:

特定のクラスのすべてのサブクラスが必要です。それを警戒と呼びましょう。直接のサブクラスで起こっていることを監視できます。この情報はクラスに保存されるため、それぞれの状態が異なります。

2 つのクラス A < B が同じ変数を変更するため、クラス変数は使用できません。サブクラスにも直接アクセスできないため、Vigilant のすべてのサブクラスに、サブクラスに関する情報を保存および取得するための容量を与える方法が必要でした。

固有クラスを開くアクセサーを定義することにより、次のように言えます。

A.singleton_class.instance_eval { attr_accessor :x }

メソッド (アクセサ) がそのスーパークラスの固有クラスに追加されたため、すべてのサブクラス Bclass B < A; endが実行できるようになり、ルックアップで見つけることができます。B.x

最初の例は、Bx が Ax と異なることを示しています。

さて、私が本当に理解していないのは、x がどこにあるかです。アクセサーではなく、変数。私がそれを行うB.instance_variables[]、 B.singleton_class.instance_variables と同じように表示されます

4

1 に答える 1

2

すべてのサブクラスに、シングルトン クラス / 固有クラスに変数を持たせたい。

申し訳ありませんが、それはあなたがここでやっていることではありません:

puts SomeSuperClass.variable # => 'This only works for the superclass'
puts SubClass.variable # => '

なぜその書き込みだと思いますか

SomeSuperClass.variable 

は、次の擬似コードと同等です。

SomeSuperClassSingletonClass.variable

または実際のコード:

SomeSuperClass.singleton_class.variable

クラスとそのシングルトン クラスは、2 つの異なるクラスです。

さらに、このコード:

  class << self
    attr_accessor :variable
    @variable = ': )' # This does't seem to have any effect   
  end

このコードと同じ方法で、その @variable のアクセサーを作成しません。

class Dog
  attr_accessor :x

  @x = 'hello'
end

puts Dog.x

...その @x 変数のアクセサを作成しません:

--output:--
undefined method `x' for Dog:Class (NoMethodError) 

attr_accessor() が行うことは次のとおりです。

class Dog
  def x
    @x
  end

  def x=(val)
    @x = val
  end

  #=====

  @x = 'hello'
end

これらのメソッドは、すべての定義の外で定義されたクラス インスタンス変数@xとは何の関係もありません。@変数は、その時点で自分自身であるオブジェクトで検索 (または設定) されます。これらの定義を呼び出すことができる唯一のオブジェクトは Dog クラスのインスタンスであるため、x は Dog クラスではなく Dog インスタンスで検索 (または設定) されます。

また、この行@x = 'hello'が実行されると、self は Dog クラスと等しいため、@x は自分自身を Dog クラスにアタッチします。

シングルトンクラスにインスタンス変数を設定するユースケースはないと思います。あなたがやろうとしているように見えるのは次のとおりです。

class SomeSuperClass
  class << self
    attr_accessor :variable
  end

  self.variable = 'hello'

  def self.inherited(subclass)
    subclass.singleton_class.instance_eval do
      attr_accessor :variable
    end

    subclass.variable = "Hi"
  end

end

class SubClass < SomeSuperClass
end

puts SomeSuperClass.variable
puts SubClass.variable


--output:--
hello
Hi

そのコードは、 と呼ばれるものを作成しますclass instance variables。の使用例があると思われる場合はsingleton class instance variables、聞いてみましょう。

于 2014-10-03T04:52:53.993 に答える