在另一个方法中定义的方法范围

时间:2015-01-01 15:59:30

标签: ruby metaprogramming

请考虑以下代码:

class Emotion
  def confused?
    def confused?
      'yes'
    end
    'no'
  end
end

am_i = Emotion.new

am_i.confused? # => "no"
am_i.confused? # => "yes"

5.times.map { Emotion.new.confused? } # => ["yes", "yes", "yes", "yes", "yes"]

说明:

  1. 第一次运行confused?会返回"no"重新定义本身。
  2. 第二次运行confused?会调用返回"yes"的新方法。
  3. 虽然上述功能很明确,但我不确定如何将两种方法定义为相同的范围

    我问的原因是:

    • 无法在方法内外以类似的方式访问变量;例如:如果我在方法内外定义@variable,它有不同的含义。
    • 我了解到方法定义发生了变化self。与外部定义相比,confused?方法的内部定义是否具有不同的范围?
    • def如何确实确定方法的定义?

1 个答案:

答案 0 :(得分:3)

  

无法在方法内外以类似的方式访问变量;例如:如果我在方法的内部和外部定义@variable,它具有不同的含义。

使用@x = y语法设置实例变量时,实例变量设置为self

  

我了解到方法定义会改变自我。不知道混淆的内部定义?方法与外界定义有不同的范围?

范围可以更改,但在这种情况下它不会。方法内self的值始终是调用该方法的对象。在您的confused?方法定义中,selfEmotion的实例。

  

def如何确定定义方法的位置?

答案(至少在MRI中)实际上有点不直观。每个范围都引用了一个"默认定义"对象不一定与self相关,并且始终是Module的实例。该范围中的def将为默认的definee定义一个方法。在ruby代码中获取默认定义的最简单方法是:

eval("def __m; end; m = method(:__m); undef __m; m.owner")

例如,在ruby程序的顶级运行它会返回Object。因此,顶级范围的默认定义为Object

以下是一些代码,可以帮助您回答有关范围的问题:

# `self` is the toplevel object
# default definee is `Object`

class X
  # `self` is X
  # default definee is also X

  @a = 1 # defines instance variable @a for `X`

  def y # defines method 'y' on X

    # `self` is an instance of X
    # default definee is X

    @b = 2 # defines instance variable @b for an instance of `X`

    def z # defines method 'z' on X

      # `self` is still an instance of X
      # default definee is still X

      @c = 3 # defines instance variable @c for an instance of `X`

    end
  end

  class << self
    # `self` is the metaclass of X
    # default definee is also the metaclass of X

    @d = 4 # defines instance variable @d for the metaclass of X
  end
end

重要的是要记住,方法始终存储在Module的实例中,其中实例变量可以存储在任何对象中(不包括基元等) nil或布尔或整数。)