繁体   English   中英

Instance_eval:为什么子类是超类

[英]Instance_eval: why the class of subclass is superclass

    def singleton_class
       class << self
         self
       end
    end

    class Human
      proc = lambda { puts 'proc says my class is ' + self.name.to_s }

      singleton_class.instance_eval do
        define_method(:lab)  do 
          proc.call
        end
      end
    end

    class Developer < Human
    end

    Human.lab # class is Human
    Developer.lab # class is Human ; oops

以下解决方案有效

def singleton_class
  class << self
    self
  end
end

class Human
  proc =  lambda { puts 'proc says my class is ' + self.name.to_s }
  singleton_class.instance_eval do
    define_method(:lab) do
      self.instance_eval &proc
    end
  end
end

class Developer < Human
end

Human.lab # class is Human
Developer.lab # class is Human ; oops

为什么Developer.lab报告它是Human? 还有什么可以让proc在调用Developer.lab时报告Developer。

闭包是在定义它的上下文中捕获self - 就像闭包应该做的那样。 因此,当它被调用时,它将使用对它捕获的上下文的引用。 闭包不是定义预期功能的理想工具。 而不是proc.call,“define_method”调用的内容应该是“puts”,proc表示我的类是'+ name.to_s'

它是微妙的,但它归结为简单地调用块(在这种情况下,它充当正常闭包, self对应于它定义的位置,即在Human ),或者使用它(直接)作为方法定义的块或instance_eval

def singleton_class
   class << self
     self
   end
end


class Human

  PROC = proc { puts 'proc says my class is ' + self.name.to_s }

  singleton_class.instance_eval do
    define_method(:lab)  do 
      PROC.call
    end
    define_method(:lab2, &PROC.method(:call))

    define_method(:lab3)  do 
      instance_eval(&PROC)
    end
    define_method(:lab4, &PROC) 
  end
end

class Developer < Human
end

Human::PROC.call  # => "class is Human"  (original closure)
Developer.lab     # Same as previous line, so "class is Human"  (original closure)
Developer.lab2    # ditto

Developer.instance_eval(&Human::PROC)  # => "class is Developer"  (instance_eval changes sets a different scope)
Developer.lab3    # Same as previous line, so "class is Developer"
Developer.lab4    # ditto

我必须仔细考虑一下它为什么会起作用,但目前它确实有效:

class Human
  proc = -> { name }

  define_singleton_method(:lab, &proc)
end

class Developer < Human; end

require 'test/unit'
class TestClosures < Test::Unit::TestCase
  def test_that_the_human_class_is_named_human
    assert_equal 'Human', Human.lab
  end
  def test_that_the_developer_class_is_named_developer
    assert_equal 'Developer', Developer.lab
  end
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM