gpt4 book ai didi

ruby-on-rails - Ruby:使用 class_eval 定义常量只能通过 const_get 找到,但不能直接通过::lookup 找到

转载 作者:行者123 更新时间:2023-12-03 23:25:52 26 4
gpt4 key购买 nike

给定一个 User 类:

class User
end
我想使用 .class_eval 定义一个新常量.所以:
User.class_eval { AVOCADO = 'fruit' }
  • 如果我尝试通过 User::AVOCADO 访问它, 我得到 uninitialized constant User::AVOCADO ,但是 User.const_get(:AVOCADO)作品。为什么?
  • 如果我在 included 中的 Rails 关注中定义一个常量方法并将关注点包含在 User 中类,我可以通过常规 :: 访问它抬头。例如:

  • module FruitConcern
    extend ActiveSupport::Concern

    included do
    AVOCADO = 'fruit'
    end

    end

    class User
    include FruitConcern
    end

    User::AVOCADO
    => 'fruit'
    但是,查找 source code对于 ActiveSupport::关注, included只是将该块存储在一个实例变量( @_included_block )中,然后它会覆盖 append_features将调用 base.class_eval(&@_included_block) .
    所以,如果它只是调用 User.class_eval同一个块,为什么 User::AVOCADO当常量定义在 included 中时有效阻止,但不是当我打电话时 User.class_eval { AVOCADO = 'fruit' }直接地?
  • 奇怪的是(见 this blog post),在做 User.class_eval { AVOCADO = 'teste' } 时,看来 Ruby 也将常量泄漏到顶层。所以:

  • User.const_get(:AVOCADO)
    => "fruit"
    AVOCADO
    => 'fruit'
    我知道块有平坦的作用域,但常量没有事先定义,我预计 class_eval更改两者 selfdefault definee到接收器。这里发生了什么?这个常量是如何在顶层和用户范围内被定义两次的?

    最佳答案

    three implicit contexts in Ruby :

  • self ,“当前对象”:隐式接收器和实例变量的作用域。
  • 默认定义:方法最终定义为 def bar没有明确的目标(即不是 def foo.bar )。
  • 恒定范围。

  • 前两个在链接的文章中得到了很好的解释。在链接的文章中 promise 了第三篇文章,但它从未出现过。很多人写过很多关于常量的文字,可惜没有人写出权威的规范,类似于yugui对默认definee所做的。
    所以,不幸的是,我也只能推测,从而无益地增加了关于这个话题的大量非权威性词语。
    块在 Ruby 中是词法范围的,它们捕获它们的词法环境。通常,这意味着块内的引用与块外的引用完全相同,就好像块不存在一样。 (当然块局部变量除外。)
    所以,
    foo { AVOCADO = 'fruit' }
    意思是一样的
    AVOCADO = 'fruit'
    当然,除非 foo以某种方式改变了评估块的上下文。我们知道 instance_eval变化 self .我们知道 class_eval变化 self和默认定义。然而,重要的是: class_eval不会更改隐式常量范围。
    因此,分配 AVOCADO = 'fruit'里面
    User.class_eval { AVOCADO = 'fruit' }
    如果它在块之外,则具有完全相同的含义:
    AVOCADO = 'fruit'
    换句话说,它与顶层的常量赋值具有相同的含义,正如我们所知,在顶层:
  • self是未命名的单例对象,通常称为 main,
  • 默认定义为 Object ,加上方法变成 private默认情况下,和
  • 隐式常量范围也是 Object .

  • 所以, AVOCADOObject 中定义.
    这意味着以下工作:
    class User
    AVOCADO
    end
    #=> 'fruit'
    因为常量查找首先在词法上“向外”(在这种情况下它失败),然后在继承层次结构中“向上”,它成功了,因为 User隐式是 Object 的子类.
    User.const_get(:AVOCADO)
    #=> 'fruit'
    也有效,因为这实际上与之前的相同,只是通过反射动态完成:它在类 User 中启动常量查找算法, 就像你写的一样
    class User
    AVOCADO
    end
    但是,这不起作用:
    User::AVOCADO
    老实说,这令人困惑,因为 AVOCADO应该继承自 Object .

    关于ruby-on-rails - Ruby:使用 class_eval 定义常量只能通过 const_get 找到,但不能直接通过::lookup 找到,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66751918/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com