从超类初始化子类的类实例变量



给定下面代码中的超类,我希望所有子类都有一些实例变量。

下面的代码做到了这一点,但未能为所有可能的子类正确初始化该变量。

我打开了超类的本征类。这是代码(也在Rubyfidle中):

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'

我想初始化所有可能的子进程。在前两次put中,只有SomeSuperClass.variable被初始化。我不知道如何为所有可能的子类初始化这个变量。有什么想法吗?

我发现的最好的解决方案是延迟初始化变量,覆盖访问器,如:

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

动机:

我需要一个给定类的所有子类,让我们称之为Vigilant,能够监控在其直接子类上发生的一些事情。这些信息存储在类中,因此每个信息都有不同的状态。

我不能使用类变量,因为两个类a<B将修改相同的变量。我也不能直接访问子类,所以我需要一种方法来赋予Vigilant的所有子类存储和检索其子类信息的能力。

通过定义打开特征类的访问者,比如:

A.singleton_class.instance_eval { attr_accessor :x }

所有子类B class B < A; end现在都可以执行B.x,因为在其超类特征类中添加了一个方法(访问器),因此可以在查找中找到。

第一个例子表明B.x不同于A.x

现在,我真正不明白的是x在哪里;变量,而不是访问器。如果我执行B.instance_variables,则显示[],与B.singleton_class.instance_variables 相同

我希望所有的子类在它们的单例类/本征类上都有一个变量。

对不起,这不是你在这里做的:

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

为什么你会认为写

SomeSuperClass.variable 

相当于伪代码:

SomeSuperClassSingletonClass.variable

或真实代码:

SomeSuperClass.singleton_class.variable

一个类和它的singleton类是两个不同的类。

此外,此代码:

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

不会为@变量创建访问器,与此代码相同:

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无关,该变量是在所有def之外定义的@变量被查找(或设置)在那个时刻的任何对象上。唯一可以调用这些def的对象是Dog类的实例,因此x将在Dog实例上查找(或设置),而不是Dog类。

还要注意,当执行@x = 'hello'行时,self等于Dog类,因此@x将自己附加到Dog类。

我认为您没有在singleton类上设置实例变量的用例。以下是你想要做的事情:

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的用例,让我们听听。

最新更新