【问题标题】:get self as invoking class in parent in Ruby在Ruby中将self作为父类中的调用类
【发布时间】:2017-07-28 12:40:59
【问题描述】:

我的第一堂课是不变的。我想让它以某种方式作为动态值工作。

class Post < ActiveRecord::Base
  TEST = ["#{self.name}", "test1"]
end


class FakePost < Post
end

rails console 中,我尝试使用FakePost 访问TEST 常量,但它仍将self 显示为“Post”对象。有什么方法可以实现吗?

当前:

irb(main):004:0> FakePost::Test

=> ["发布", "test1"]

但是当我通过 Post 而不是 vi FakePost 访问 Constant 时,我想返回这个结果。

预期:

irb(main):004:0> FakePost::Test

=> ["FakePost", "test1"]

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 constants self


    【解决方案1】:

    问题是代码TEST = ["#{self.name}", "test1"] 仅在Post 类被实例化时被解释一次。之后它将被固定为["Post", "test1"]

    在我的脑海中,我想不出一种用常量来完成这项工作的方法,但如果你用类方法替换它,它就可以正常工作:

    class Post
      def self.TEST
        [self.name, "test1"]
      end
    end
    
    class FakePost < Post
    end
    
    Post.TEST
    #=> ["Post", "test1"]
    
    FakePost.TEST
    #=> ["FakePost", "test1"]
    

    这样做的原因是类方法中的代码是在运行时解释的(即当您调用方法时),而不是在解释类时。两种情况的时间线如下:

    TEST 常量:

    1. Post 类被逐行实例化和解释。
    2. self.name 被解释并返回 'Post',因为 self 当前是 Post 类。
    3. Post::TEST 不可撤销地设置为 ["Post", "test1"]
    4. FakePost类被实例化并继承自Post,包括["Post", "test1"]的已经实例化的TEST常量
    5. FakePost::TEST == Post::TEST == ["Post", "test1"] #=&gt; true

    TEST类方法:

    1. Post 类逐行实例化和解释。
    2. 添加了 Post 类方法 TEST(但尚未解释)。
    3. FakePost 类被实例化并从Post 继承TEST 类方法。还没有被解释。
    4. 当您运行Post.TESTFakePost.TEST 时,该方法最终将被解释。 self 现在将是 PostFakePost,具体取决于哪个类调用了 TEST 方法。

    【讨论】:

    • 感谢您的回答,但我已经知道这个答案,但是如果我要进行任何更改,则需要很多地方和检查,因此我在这里提出问题。我想要一个可行的解决方案。
    • @user4510998 据我所知,这不可能按照您想要的方式进行 - 请参阅我的编辑中的时间线,因为这不起作用。
    • 谢谢,创建使用大写创建方法的最佳实践是什么?
    • 好点,不,不是!我只是想展示相似之处。通常,类方法首选小写。
    【解决方案2】:

    常量不能被修改,所以当你在后继中引用它时,它会返回已经赋值的值。使用类方法。

    class Post < ActiveRecord::Base
      def self.test
        ["#{self.name}", "test1"] 
      end
    end
    
    class FakePost < Post
    end
    

    【讨论】:

      【解决方案3】:

      正如其他人所指出的,TEST 在解析Post 时被设置为等于["Post", "test1"];这与简单的TEST = ["Post", "test1"] 没有什么不同。

      要从常量 (TEST) 获得所需的结果,一种可能性是将 TEST 设置为等于一个 proc,然后使用 self 作为参数调用该 proc。这可以按如下方式完成。

      class News
        TEST = ->(slf) { ["#{slf}", "test1"] }
      end
      
      class FakeNews < News
      end
      
      News.instance_eval { self::TEST[self] }
        #=> ["News", "test1"]
      FakeNews.instance_eval { self::TEST[self] }
        #=> ["FakeNews", "test1"]
      

      需要BasicObject#instance_eval 才能使self 等于instance_eval 的接收者。 Proc#[]Proc#call 相同(以及 Proc.yieldProc#=== 和已贬值的 Proc#() [写为 TEST.(self)])。任君挑选!

      【讨论】:

        猜你喜欢
        • 2018-06-28
        • 1970-01-01
        • 2015-03-03
        • 2021-03-31
        • 2021-06-05
        • 1970-01-01
        • 1970-01-01
        • 2014-08-24
        • 2014-10-14
        相关资源
        最近更新 更多