【问题标题】:Class level constant broken in Ruby 2.3.4Ruby 2.3.4 中的类级别常量被破坏
【发布时间】:2017-05-18 06:40:06
【问题描述】:

我有一些代码可以简化为以下内容。它适用于 Ruby 2.3.3 并在 2.3.4 上中断。这有点奇怪,我欢迎就如何重写它提出建议以及解释它为什么会中断。

require 'forwardable'

class Dummy
  class << self
    TEST = {
      a: Dummy.new,
      b: Dummy.new
    }

    extend Forwardable

    def_delegators :TEST, :[]

    private :new
  end
end

puts Dummy[:a]

Ruby 2.3.3

#<Dummy:0x007fbd6d162380>

Ruby 2.3.4

NameError: uninitialized constant TEST

目标是只初始化一次TEST 并让.new 成为私有的。在 [] 方法中记忆 @test 变量不起作用,因为 new 在创建哈希时是私有的。

编辑

从等式中删除 Forwardable 可以解决问题,但我仍然很好奇为什么以及如何改进它的想法。

class Dummy
  class << self
    TEST = {
      a: Dummy.new,
      b: Dummy.new
    }

    def [](key)
      TEST[key]
    end

    private :new
  end
end

puts Dummy[:a]

Ruby 2.3.3 和 2.3.4

#<Dummy:0x007fbd6d162380>

【问题讨论】:

  • 顺便说一句,您不需要将常量放在 class &lt;&lt; self 块中。即使在外面也会被实例化一次。

标签: ruby ruby-2.3


【解决方案1】:

如何解决

require 'forwardable'

class Dummy
  Test = {
    a: Dummy.new,
    b: Dummy.new
  }

  class << self
    extend Forwardable

    def_delegators :"::Dummy::Test", :[]

    private :new
  end
end

puts Dummy[:a]

为什么

Ruby 是开源的。有一个bug #12478,固定在that commit。提交的消息明确指出它在处理非模块对象时会改变行为。

符号不再是not convertedStrings 并单独处理,:TEST 不在Dummy 级别和常量could not be resolved in different context 上扩展。

为什么它不是错误

在单例类上声明常量没有任何意义(检查你的旧代码):

Dummy.constants
#⇒ []
Dummy.singleton_class.constants
#⇒ [:TEST]

这个常量在旧版实现中被成功解析,就像将两个负数相乘得到一个正数结果:错误被否定了。该代码无法正常工作,它偶尔会以意想不到的方式失败两次,但值得赞赏的是,产生了正确的结果。

【讨论】:

  • 在单例类上声明它的原因是让它不可访问。 TEST 是通过[] 访问的数据的隐藏容器。它作为一个局部范围的变量是不变的,不会改变,而不是像类或模块名称那样的常量。
  • “它作为局部范围的变量是常量”——我相信你误解了 ruby​​ 的惯用概念。试试class Dummy2 &lt; Dummy; end; Dummy2.singleton_class::TEST。在 ruby​​ 中确实有 nothing 不可访问。 Ruby 推动合同。需要这样的合同吗?——在private :new 附近发出private_constant :Test。后者仍然不会使其无法访问。还有private :new:试试Dummy.send :new
  • 是的,我知道你仍然可以得到它,但是通过把它放在我做的地方我打算表明该合同不是假定 被访问。我不知道private_constant,所以也许这是一个更好的方法。
猜你喜欢
  • 1970-01-01
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
  • 2020-02-15
  • 2014-01-09
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多