【问题标题】:Ruby Dynamic Classes. How to fix "warning: class variable access from toplevel"Ruby 动态类。如何修复“警告:从顶层访问类变量”
【发布时间】:2011-12-22 08:47:16
【问题描述】:

我正在尝试编写一个基于从文件读取的配置动态定义 ruby​​ 类的程序。我知道我可以使用 Class.new 来做到这一点。这是一个示例程序:

x = [1,2,3]

Test = Class.new do
  @@mylist = x

  def foo
    puts @@mylist
  end
end

Test.new.foo

当我运行它时,我得到以下输出(使用 ruby​​ 1.9.3p0 运行):

c:/utils/test.rb:4: 警告:从顶层访问类变量
c:/utils/test.rb:7: 警告:从顶层访问类变量
1
2
3

有谁知道导致这些警告的原因以及如何消除它们?

我已经尝试替换 tjhat 的行

@@mylist = x

有了这个

class_variable_set(:@@mylist, x)

但是当我这样做时,我得到了这个错误:

c:/utils/test.rb:7: 警告:从顶层访问类变量
c:/utils/test.rb:7:in `foo': 对象中未初始化的类变量@@mylist (NameError)
        来自 c:/utils/test.rb:11:in `'

提前致谢!

【问题讨论】:

    标签: ruby oop dynamic warnings


    【解决方案1】:

    这并没有做你认为它正在做的事情。由于您没有使用class 关键字创建类,因此您的类变量设置为Object,而不是Test。这样做的影响非常大,这就是 Ruby 警告您的原因。类变量在祖先之间共享,对象通常继承自Object

    【讨论】:

      【解决方案2】:

      为了消除这个警告,你应该使用class_variable_set 方法:

      x = [1,2,3]
      
      Test = Class.new do
        class_variable_set(:@@mylist, x)
      
        def foo
          puts @@mylist
        end
      end
      

      【讨论】:

      • 不幸的是,这给了我一个错误。我已经用详细信息更新了原始问题。
      • 嗯——只有 Ruby 1.9.2 可能会给你一个关于“从顶层访问类变量”的警告。但是NameErroruninitialized class variable 消息可能只来自Ruby 1.8,因为方法class_variable_set 在这个版本中是私有的。也许这是个愚蠢的问题 :) 但你确定你在同一个 ruby​​ 版本中运行这两个版本吗?如果我将 1.8 与您的初始 sn-p 一起使用,我没有任何警告消息,如果我将 1.9 与我的 sn-p 一起使用,它似乎也可以...
      • 感谢 WarHog。我刚刚在 1.9.2p290 上尝试了您的代码,并且没有任何错误。但是当我用 1.9.3p0 运行它时,我得到了上面描述的错误。我将看看 1.9.3 的新增功能,看看是否有任何东西可以解释行为上的差异。
      • 可能是问题 3080 (redmine.ruby-lang.org/issues/3080) 导致我在 1.9.3 上出现问题。似乎是一种回归。
      • 另一种可能的解决方案是使用类方法来访问类变量,这里也有描述stackoverflow.com/a/21444098/1145454
      【解决方案3】:

      在声明类时,与其在类上定义“mylist”类变量,不如稍后在其上声明类级变量,如下所示。显示了两种不同的方法。前者仅适用于 1.9,后者适用于两个版本,但不那么惯用。

      x = [1,2,3]
      
      Test = Class.new do
        def foo
          puts @@mylist
        end
      end
      
      # ruby 1.9.2
      Test.class_variable_set(:@@mylist, x)   
      
      # ruby 1.8.7
      Test.class_eval {
        @@mylist = x
      }
      
      Test.new.foo
      

      【讨论】:

      • 感谢您的回复。不幸的是,当使用 1.9.3 运行时,第一个版本会导致我看到的错误,而第二个版本会出现我收到的警告!我开始怀疑这是 ruby​​ 1.9.3 中行为/回归的变化。
      【解决方案4】:

      如果你只想抑制这个警告,你可以使用

      $VERBOSE = nil
      

      在你的代码之上

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-14
        • 1970-01-01
        • 2017-04-22
        • 1970-01-01
        • 1970-01-01
        • 2011-06-08
        • 2017-12-29
        相关资源
        最近更新 更多