【问题标题】:Dynamically resolve class to global scope将类动态解析为全局范围
【发布时间】:2018-06-19 07:25:53
【问题描述】:

我需要将一个类的引用保存到一个哈希中:

@hash['foo'] = bar if bar.is_a?(Class)

上面这段代码在我的/lib目录下,它不是每次都自动加载的,bar通常是一个自动加载的类。为了避免在我reload!我的代码时出现“xxx的副本已从模块树中删除但仍处于活动状态”错误,我试图将bar解析为全局范围,即:添加@987654326 @ 在类名之前(Baz 正在变为 ::Baz)。

我不确定如何在将类转换为字符串、添加::,然后将其转换回类的情况下动态执行此操作。

【问题讨论】:

  • 常量在赋值时被解析。就像A = 1; hash['a'] = A; A = 2 - 常量和散列之后指的是不同的对象。添加:: 不会改变任何东西。
  • 我明白了。那么我该如何克服我的问题中提到的错误呢?
  • 要么通过存储常量的名称并使用const_get / constantize(这是您试图避免的),要么通过使用 proc,例如@hash['foo'] = -> { Baz } 可以通过@hash['foo'].call动态解析
  • 看起来很公平。您可以提交它作为答案吗?我愿意接受!

标签: ruby-on-rails ruby class autoload


【解决方案1】:

将常量分配给哈希时,常量在分配时解析:(不是特定于哈希,这正是常量的工作方式)

hash = {}
A = 1
hash[:a] = A
#=> 1          # <- 1 is being assigned, not A

A = 2
hash[:a]
#=> 1

解决它的一种方法是存储常量的名称:

hash = {}
A = 1
hash[:a] = 'A'
#=> 'A'

并通过const_get/constantize解决它:

A = 2
Object.const_get(hash[:a])
#=> 2

这也适用于嵌套常量:

hash[:pi] = 'Math::PI'
Object.const_get(hash[:pi])
#=> 3.141592653589793

如果你的对象恰好是一个命名类(或模块),你可以通过Module#name检索它的名字:

hash[:lazy_enum] = Enumerator::Lazy.name
#=> "Enumerator::Lazy"

Object.const_get(hash[:lazy_enum])
#=> Enumerator::Lazy

另一种方法是使用 proc 引用其块中的常量:

hash = {}
A = 1
hash[:a] = -> { A }
#=> #<Proc:0x00007fc4ba05f510@(irb):10 (lambda)>

调用块时会解析常量:

A = 2
hash[:a].call
#=> 2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    相关资源
    最近更新 更多