Ruby 常量在另一个类中调用时返回 nil

Ruby constant returning nil when called in another class

提问人:Nnamdi 提问时间:8/26/2022 最后编辑:Nnamdi 更新时间:8/27/2022 访问量:64

问:

我有这个班级

class Foo
  MAIN_COMPUTER = @computer_name
  attr_accessor :computer_name

  def initialize
    @computer_name = "IComputer"
  end
end

当我尝试在另一个类的方法中访问 MAIN_COMPUTER 变量时,即使 Foo 类的对象已被初始化,它也会返回 nil

class Gamer
  def opponent
    Foo::MAIN_COMPUTER
  end
end

me = Gamer.new

me.opponent 返回 nil。有没有办法让 Foo::MAIN_COMPUTER 从对手方法定义中引用“IComputer”?有没有其他方法可以实现这一目标?

任何帮助将不胜感激。先谢谢你!

编辑 1

class Foo
  attr_accessor :computer_name

  def initialize
    @computer_name = "IComputer"
  end

  def self.main_computer
    @computer_name
  end
end

class Gamer
  def opponent
    Foo.main_computer
  end
end

me = Gamer.new
p me.opponent

代码的最后一行返回 nil。请您解释一下吗?谢谢

Ruby OOP 命名空间 常量

评论

3赞 Stefan 8/27/2022
Foo::MAIN_COMPUTER总是在这里,不管你从哪里称呼它。那是因为只会将 from (此时) 的分配给常量。它不会将常量“链接”到变量。此外,前者是类实例变量,而后者(内部)是“正常”实例变量。nilMAIN_COMPUTER = @computer_name@computer_namenil@computer_nameinitialize
1赞 Stefan 8/27/2022
你能解释一下你的代码应该实现什么吗?看起来您希望常量和实例变量具有/共享相同的值。为什么要冗余?你想做什么?
0赞 Nnamdi 8/27/2022
我正在使用的代码有点复杂,所以我尝试用我在这里发布的代码进行简化。假设我创建了一个新的 Foo 对象,我希望 Foo::MAIN_COMPUTER 引用“IComputer”。有没有办法做到这一点?有趣的是你说的类实例变量。我会对此进行研究
0赞 Stefan 8/27/2022
如果您使用不同的实例创建另一个实例,该怎么办 - 常量是否应该更改?还是应该只有第一个实例设置它?如果是这样,当还没有创建实例时,有什么价值?Foocompurer_nameMAIN_COMPUTER
0赞 Pedro Paiva 8/27/2022
你对在这个 Foo 类中使用单例模式有什么想法?refactoring.guru/design-patterns/singleton/ruby/example

答:

1赞 Stefan 8/27/2022 #1

从您的评论来看,您似乎希望拥有单个实例和一些可以全局引用的“主”实例。FooFoo

常量不应该改变(因此得名),所以如果你想让“main”对象是可改变的,你可能应该改用类方法。

要向类本身添加属性,请执行以下操作:

class Foo
  class << self
    attr_accessor :main_computer
  end

  attr_accessor :computer_name

  def initialize(computer_name)
    @computer_name = computer_name
  end
end

调用 within 将创建两个方法:一个 getter 和一个 setter 。该值将存储在名为的类实例变量中(即直接在类内部,而不是其实例中)。attr_accessor :main_computerclass << selfFoo.main_computerFoo.main_computer=@main_computer

初始值为:nil

Foo.main_computer
#=> nil

您现在可以创建一个新实例,然后将其分配给:Foomain_computer

foo = Foo.new("HAL 9000")
#=> #<Foo:0x00007f81321827d8 @computer_name="HAL 9000">

Foo.main_computer = foo

这将允许您从另一个类引用该实例:

Foo.main_computer
#=> #<Foo:0x00007f81321827d8 @computer_name="HAL 9000">

或者,要获得它的名字:

Foo.main_computer.computer_name
#=> "HAL 9000"

您还可以将初始值设定项分配给:Foomain_computer

def initialize(computer_name)
  @computer_name = computer_name
  Foo.main_computer = self
end

若要仅在已存在 no 时进行分配,请使用条件分配:main_computer

def initialize(computer_name)
  @computer_name = computer_name
  Foo.main_computer ||= self
end