【问题标题】:Tricky Ruby scoping issue [duplicate]棘手的Ruby范围问题[重复]
【发布时间】:2016-02-09 20:27:33
【问题描述】:

为什么这个小小的 Ruby 代码 sn-p 不起作用?

cached = {}
def cache(*key)
  cached[key.join] ||= yield
end
cache("key") do "value" end

我收到以下错误:

NameError: undefined local variable or method `cached' for main:Object

有什么想法吗?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    使用实例变量代替局部变量:

    @cached = {}
    def cache(*key)
      @cached[key.join] ||= yield
    end
    

    你不能在你的缓存方法中使用局部变量cached,因为局部变量在方法定义之外是不存在的,所以如果你之前没有在方法体或者方法参数中定义局部变量,Ruby就找不到了。 更多关于变量可见性here.

    【讨论】:

    • 哈哈,哇,脑残……你说得对,谢谢!
    • 问题是,为什么代码不起作用?而不是如何使它工作?
    • 添加原因说明。
    【解决方案2】:

    我会尝试补充@ProgNoob 的答案。

    如果您来自 CC++ 等语言,其中使用代码块创建范围。

    {
       ....
    }
    

    并且该范围内的所有局部变量在外部都是不可见的,但在内部创建的每个范围内都是可见的,例如:

    {
      int a = 3;
      {
         // a is visible inside here
      }
      // a is visible inside here
      ...
    }
    // a is not visible outside the scope
    

    Ruby 处理事情的方式不同。当您创建 classmodulemethod 时,您正在创建一个全新的范围,而不是从上面的范围中获取任何东西,就像我们在 C 中看到的那样。

    v0 = 0
    class SomeClass # Scope gate
      v1 = 1      
      # only v1 is visible here
    
      def some_method # Scope gate
        v2 = 2
        # only v2 is visible here        
      end # end of def scope gate
    end # end of class scope gate
    

    打破范围之门:

    • 带有Class.new 的类定义
    • Module.new 的模块定义
    • 带有define_method的方法定义

    前面没有范围门的例子

    v0 = 0
    SomeClass = Class.new do
      v1 = 1
      # v0 and v1 visible here
    
      define_method(:some_method) do
        v2 = 2
        # v0, v1 and v2 visible here
      end
    end
    # v0 only visible here
    

    【讨论】:

    • 感谢您的详细解释。我的问题是我在 foo = {}; whatever do (here I use foo) end 这样的块内使用变量,但后来当我尝试在方法中使用它时,它是未定义的。我现在看到了我的错误。
    猜你喜欢
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多