为什么回退机制不适用于此?

时间:2013-11-14 20:49:04

标签: ruby

当访问变量时,Ruby中的回退机制首先查找局部变量,如果找不到,则会自动应用self并查找实例变量。但是,以下代码不起作用:

class My
  def init
    @abc = "abc"
  end

  def pt
    puts abc
  end
end

当我尝试在实例上调用pt时收到此错误消息:

2.0.0-p247 :009 > my = My.new
 => #<My:0x007f9b5a1b1000> 
2.0.0-p247 :010 > my.init
 => "abc" 
2.0.0-p247 :011 > my.pt
NameError: undefined local variable or method `abc' for #<My:0x007f9b5a1b1000 @abc="abc">

但是,@abc作为对象中的实例变量存在:

2.0.0-p247 :012 > my.instance_variables
=> [:@abc] 

那么为什么pt找不到abc呢?它不应该自动查找实例变量,因为它没有在本地定义,并打印出来吗?

注意:

我知道使用puts @abc会有效,但这不是我的问题。我的问题是Ruby中的回退机制。此代码有效:

2.0.0-p247 :079 > class My
2.0.0-p247 :080?>     def initialize(param)
2.0.0-p247 :081?>         @abc = param
2.0.0-p247 :082?>       end
2.0.0-p247 :083?>   
2.0.0-p247 :084 >       def printabc
2.0.0-p247 :085?>         puts abc
2.0.0-p247 :086?>       end
2.0.0-p247 :087?>   end

2.0.0-p247 :089 > My.new("haha").printabc
haha

我不知道为什么它在前一种情况下不起作用,但在后一种情况下起作用。

1 个答案:

答案 0 :(得分:3)

执行以下操作(您错过了@符号)

def pt
    puts @abc
end
  

那么为什么pt在这里找不到abc?

当您使用attr_accessorattr_reader时,您将会发生什么。见下文相同。在这种情况下,ruby将首先检查是否创建了名称为abc的任何局部变量,但是当它找不到它时,检查是否存在名称为abc的方法,将消息abc传递给selfself.abc)。现在attr_reader定义了一个方法def abc; @abc ;end(它也是attr_accessor的两种方法之一)。因此没有错误,你得到@abc的输出。

class My
  attr_accessor :abc
  def init
    @abc = "abc"
  end

  def pt
    puts abc
  end
end

my = My.new
my.init # => "abc"
my.pt
# >> abc

请记住,只有像foo这样的裸呼叫时,Ruby总会首先检查它是否是本地变量。如果在找到它的范围内找不到名称为foo的局部变量,则会检查它是否为方法。请参阅下面的一个演示示例来实现这一事实:

x = 10
def x ;11;end
x # => 10