Ruby:继承使用类变量的代码 [英] Ruby: Inherit code that works with class variables

查看:19
本文介绍了Ruby:继承使用类变量的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情况:我有多个类,每个类都应该保存一个带有配置哈希的变量;每个类的哈希值不同,但类的所有实例都相同.

The situation: I have multiple classes that should each hold a variable with a configuration hash; a different hash for each class but the same for all instances of a class.

起初,我是这样尝试的

class A
  def self.init config
    @@config = config
  end

  def config
    @@config
  end
end

class B < A; end
class C < A; end

但很快注意到它不会那样工作,因为@@config 保存在 A 的上下文中,而不是 B 或 C 的上下文中,因此:

But soon noticed that it wouldn't work that way because @@config is held in the context of A, not B or C, thus:

B.init "bar"
p B.new.config  # => "bar"
p C.new.config  # => "bar" - which would be nil if B had it's own @@config

C.init "foo"
p B.new.config  # => "foo" - which would still be "bar" if C had it's own @@config
p C.new.config  # => "foo"

我想过这样使用它:

modules = [B, C]
modules.each do |m|
  m.init(@config[m.name])
end
# ...
B.new  # which should then have the correct config

现在,我很清楚为什么会发生这种情况,但我不确定会出现这种情况的原因.

Now, it's clear to me why that happens, but I'm not sure about the reason for it being like this.

它不能以另一种方式工作,在子类的上下文中保存类变量吗?

Couldn't it work the other way too, holding the class variable in the context of the subclass?

我还发现令人恼火的是,即使在超类中"调用时,self 也始终是子类.由此,我首先期望来自超类的代码在子类的上下文中执行".

What i also found irritating was the fact that self is always the subclass even when called 'in' the superclass. From this, I first expected the code from the superclass is "executed in the context of" the subclass.

对此的一些启发将不胜感激.

Some enlightenment about this would be greatly appreciated.

另一方面,我可能不得不接受这样的工作方式,我必须找到另一种方法来做到这一点.

On the other hand, I likely have to accept it works that way and that I have to find another way to do this.

有没有一种元"的方式来做到这一点?(我尝试过 class_variable_set 等,但没有运气)

Is there a "meta" way to do this? (I tried with class_variable_set etc. but with no luck)

或者,也许init"方法的整个想法一开始就有缺陷,还有其他一些模式"可以做到这一点?

Or maybe is the whole idea of that 'init' method flawed in the first place and there's some other "pattern" to do this?

我可以让@@config 成为散列,保存所有配置并始终选择正确的配置,但我发现这有点尴尬..(不是继承可以解决此类问题吗?;)

I could just make @@config a hash, holding all the configs and always pick the right one, but I find that a little awkward.. (isn't inheritance there to solve this kind of problem? ;)

推荐答案

@@variables 不是类变量.它们是类层次结构变量,即它们在整个类层次结构之间共享,包括所有子类和所有子类的所有实例.(有人建议将 @@variables 更像 $$variables,因为它们实际上与 $globals 有更多共同点与 @ivars 相比.这样可以减少混淆.其他人已经走得更远,建议将它们从语言中删除.)

The @@variables aren't class variables. They are class hierarchy variables, i.e. they are shared between the entire class hierarchy, including all subclasses and all instances of all subclasses. (It has been suggested that one should think of @@variables more like $$variables, because they actually have more in common with $globals than with @ivars. That way lies less confusion. Others have gone further and suggest that they should simply be removed from the language.)

Ruby 没有类变量,比如 Java(它们被称为静态字段)有它们.它不需要需要类变量,因为类也是对象,因此它们可以像任何其他对象一样具有实例变量.您所要做的就是删除无关的 @ .(并且您必须为类实例变量提供访问器方法.)

Ruby doesn't have class variables in the sense that, say, Java (where they are called static fields) has them. It doesn't need class variables, because classes are also objects, and so they can have instance variables just like any other object. All you have to do is to remove the extraneous @s. (And you will have to provide an accessor method for the class instance variable.)

class A
  def self.init config
    @config = config
  end

  def self.config # This is needed for access from outside
    @config
  end

  def config
    self.class.config # this calls the above accessor on self's class
  end
end

让我们稍微简化一下,因为 A.config 显然只是一个 attribute_reader:

Let's simplify this a bit, since A.config is clearly just an attribute_reader:

class A
  class << self
    def init config
      @config = config
    end

    attr_reader :config
  end

  def config
    self.class.config
  end
end

而且,事实上,A.init 只是一个名字很有趣的 writer,所以让我们将它重命名为 A.config= 并使它成为一个 writer,反过来意味着我们的方法对现在只是一个访问器对.(显然,由于我们更改了 API,测试代码也必须更改.)

And, in fact, A.init is just a writer with a funny name, so let's rename it to A.config= and make it a writer, which in turn means that our pair of methods is now just an accessor pair. (Since we changed the API, the test code has to change as well, obviously.)

class A
  class << self
    attr_accessor :config
  end

  def config
    self.class.config
  end
end

class B < A; end
class C < A; end

B.config = "bar"
p B.new.config  # => "bar"
p C.new.config  # => nil

C.config = "foo"
p B.new.config  # => "bar"
p C.new.config  # => "foo"

但是,如果您真的需要的话,我无法摆脱这样一种感觉,即设计中有一些更根本的问题.

However, I can't shake the feeling that there is something more fundamentally iffy about the design, if you need this at all.

这篇关于Ruby:继承使用类变量的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆