Ruby Module无法访问本地变量

时间:2017-03-24 03:42:04

标签: ruby scope

是否可以从foo访问GetVar.print_foo

foo = "test"

module GetVar
    def self.print_foo
        puts foo
    end
end

GetVar.print_foo

我可以通过将foo更改为常量FOO来使其工作,但这更像是一个黑客,我正在寻找更好的解决方案。我也不能,或者更不愿意,将foo变为实例变量@foo

2 个答案:

答案 0 :(得分:1)

简单的答案是:不,没有办法从foo方法的方法范围访问脚本范围中的局部变量print_foofoo是一个局部变量,局部变量是它们定义的范围的局部变量,这就是为什么它们被称为" local"毕竟是变量。

foo在脚本范围中定义。它没有在print_foo的方法范围中定义,因此无法从print_foo访问它。

Ruby中有四个局部变量作用域:脚本,模块/类定义,方法定义和lambda文字/块体。在这四个中,脚本范围,模块/类范围和方法范围创建新范围。 Lambda文字和块,以及这两个创建嵌套范围,可以从其周围的词法范围访问局部变量。

因此,在foo中访问print_foo的唯一方法是确保print_foo在嵌套范围内定义,即在块中定义,以及所有周围环境范围也是块。值得庆幸的是,有一种方法可以定义一个名为Module#define_method的方法(或者在这种情况下实际上是Object#define_singleton_method),它采用一个块,并且有一种方法可以定义一个名为Module::new的模块。一个街区:

是否可以从foo访问GetVar.print_foo

foo = "test"

GetVar = Module.new do 
  define_singleton_method(:print_foo) do puts foo end
end

GetVar.print_foo
# test

实际上,我们甚至不需要Module::new的块形式:

foo = "test"

GetVar = Module.new.tap do |m| m.define_singleton_method(:print_foo) do puts foo end end

GetVar.print_foo
# test

答案 1 :(得分:0)

使用class_eval

class A
  @foo = "test"
end
module GetVar
  def self.print_foo
      A.class_eval do
        puts @foo
      end
  end
end
GetVar.print_foo
#=> "test"

或展平范围

foo = "test"
GetVar = Module.new do
  # define a class method
  define_singleton_method :print_foo do
    puts foo
  end
end
GetVar.print_foo
#=> "test"

请参阅此问题:How to understand the difference between class_eval() and instance_eval()?