【问题标题】:Which class does a method defined inside a block belong to?块内定义的方法属于哪个类?
【发布时间】:2018-07-24 11:45:51
【问题描述】:

这是一堂课

class Foo
  def test_method(&c)
    puts "inside test method"
    c.call
  end
end 

现在,如果我在块内定义一个方法

f = Foo.new
f.test_method do 
  def m1
    puts "inside the method m1 defined inside the block"
  end
  puts m1.class
end

块的输出是NilClass

如果一个方法是在一个类之外定义的,那么它将成为类Object 内的一个私有方法。为什么在块中定义的方法会成为NilClass 的一部分,而不是Foo 类的一部分?

【问题讨论】:

    标签: ruby ruby-2.3


    【解决方案1】:

    首先m1返回puts的结果,即nil

    其次,在您当前的代码中,m1 方法是为 Object 类定义的,因为默认情况下 block 仍然是它的上下文,不仅对于局部变量(它总是如此),而且对于“当前对象”和'当前班级'。如果您希望您的定义按预期工作,您可以使用class_eval,它会更改块内的当前类(在不同的上下文中执行此块:

    class Foo
      def test_method(&c)
        puts 'inside test method'
        self.class.class_eval(&c)
      end
    end
    f = Foo.new
    f.test_method do
      def m1
        # anything
      end
    end
    
    Foo.instance_methods.grep(/m1/)
    # => [:m1]
    f.m1
    # => not an error
    Object.new.m1
    # => NoMethodError: undefined method `m1' for #<Object:0x00000001c9b4f8>
    

    【讨论】:

    • @mudasobwa 公平点,我编辑了我的答案。原来instance_eval 添加了m1 方法作为调用instance_eval 的对象的单例方法。
    • 我在 Sinatra 与助手一起工作。在 Sinatra 中,帮助程序在帮助程序块中定义 - helpers do ... end。根据您在此处提到的技术,这是否有效?
    • @dhaliman 据我所知,是的,确实如此:github.com/sinatra/sinatra/blob/…
    【解决方案2】:

    如果你想检索定义方法的类,你应该明确地这样做:

    Foo.new.test_method do 
      def m1; :content_does_not_matter; end
      puts method(:m1).inspect
    end  
    #⇒ #<Method: Object#m1>
    

    可能会使用Method#owner 来检索所有者:

    method(:m1).owner
    #⇒ Object
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-02
      • 2017-06-10
      • 2011-04-25
      • 1970-01-01
      • 2020-04-19
      • 2012-11-01
      相关资源
      最近更新 更多