为什么在使用常量时会得到未定义的局部变量或方法错误,但在使用方法时却没有?

时间:2016-12-28 18:41:06

标签: ruby inheritance constants

如果我有一个类似的话怎么样?

class Thing
  def number
    10
  end
end

我继承了这样:

class OtherThing < Thing
  CONSTANT = number / 2
end

当我尝试实例化类时,我得到undefined local variable or method 'number',但如果我这样做:

   class OtherThing < Thing
     def method_instead_of_constant
       number / 2
     end
   end

有效吗?

修改

我不一定要找一个黑客去做这个工作,而是要理解为什么它没有。 mudasobwa下面的答案帮助最多;常量是在类级别分配的,而不是在实例上分配。

4 个答案:

答案 0 :(得分:3)

因为numberThing上的实例方法。 OtherThing的类定义的范围是Class的实例,这意味着它在定义时不是Thing的实例或OtherThing的实例。

那就是说,你不应该通过执行方法来定义常量。你可能有一个计算的类变量,你打电话给freeze以防止在启动后编辑,但即使这不是一个非常常见的模式。

答案 1 :(得分:2)

您需要一个类方法来实现您正在寻找的功能:

class Thing
  #   ⇓⇓⇓⇓   HERE
  def self.number
    10
  end
end

class OtherThing < Thing
  CONSTANT = number / 2
end

CONSTANT赋值发生在类级别,因此它可以访问Thing的类方法,但不能访问它的实例方法。

另一方面,您可以实例化Thing,然后在其上调用实例方法:

class Thing
  def number
    10
  end
end

class OtherThing < Thing
  #          ⇓⇓⇓⇓⇓⇓⇓⇓⇓  HERE
  CONSTANT = Thing.new.number / 2
end

答案 2 :(得分:1)

由于范围。

根据动态范围评估方法调用,并区分类和实例范围。常量在词法范围内被解析,并且不像方法那样区分类和实例范围。

class A
  # expressions are evaluated in scope of class A
  def m
    # expressions are evaluated in scope of an instance of A
    return 42
  end
end

类和实例不一样。

A 
a = A.new

A.class # => Class
a.class # => A

A.respond_to?(:m) # => false
a.respond_to?(:m) # => true

A.m # => raises NoMethodError
a.m # => 42

因此,在类体中,您无法调用实例方法。

然而,使用词法范围查找常量,即源文件中类和模块的周围上下文。

module M
  # can access global constants and those defined in M
  class A
    # can access global constants and those defined in M or A
    def m
      # can access global constants and those defined in M or A
    end
  end
end

您可以使用Module.nesting

检查当前常量查找路径

答案 3 :(得分:1)

  

我不一定要找一个黑客来完成这项工作,但是[原文如此]   了解它为什么没有。

以下是错误消息:

undefined local variable or method 'number'

当Ruby解释器看到number时,它会查找局部变量或名为number的方法。在方法的上下文中,解释器将number读为self.number。所以这一行:

CONSTANT = number / 2

实际上被视为:

CONSTANT = self.number / 2

那么self是什么?

那取决于你明确或隐含地定义它的位置。在类块中,self是类本身,即OtherThing。由于OtherThing或其任何祖先都没有定义类方法number,因此也没有变量number,因此Ruby会抛出错误消息。

实例方法定义中定义的

self是当前对象。但如果没有实例和更多理论,这是非常抽象的。其他相关主题是 Singleton-Classes 继承。如果您喜欢书籍,那么我推荐 David A. Black The Well-Grounded Rubyist 2nd Ed,第5章。再想一想,读一读全书。