【问题标题】:When does a local variable become accessible?局部变量什么时候可以访问?
【发布时间】:2019-07-31 13:05:24
【问题描述】:

这是来自 ruby​​-doc 第 4.3 节中给出的示例,在以下链接中:

Ruby-Doc

解释是这样的:

Ruby 寻找赋值语句。如果在源代码中的某个点之前使用a'' it sees it being assigned to, it decides to parsea'' 作为变量,否则将其视为方法。

示例如下

def a
  print "Function 'a' called\n"
  99
end

for i in 1..2
  if i == 2
    print "a=", a, "\n"
  else
    a = 1
    print "a=", a, "\n"
  end
end

输出为

a=1
Function 'a' called
a=99

但是从代码中可以明显看出,当 i 为 1 时,a 被分配给 1,并且 1 被打印为 a 的值。然后对于 i = 2,调用方法“a”。

现在如果我在 for 循环之外打印 'a' 会发生什么?我得到了值 1,但我不知道这怎么可能。如果从之前的方法值重新分配 a 到 1 会在任何地方改变它,那么在 i = 2 期间,输出也应该是 1。如果我错了,请纠正我。

【问题讨论】:

    标签: ruby


    【解决方案1】:

    未到达的代码分支中的赋值语句确实会影响局部变量。

    class Foo
      def method_missing(meth, *args)
        "returned from method_missing #{meth}"
      end
    end
    
    Foo.new.instance_exec do
      puts abc.inspect # abc is considered a method
    
      if true == false
        abc = 1 # <-- this should never be reached
      end
    
      puts abc.inspect # abc is considered a local variable
    end
    

    这个输出:

    "returned from method_missing abc" # <- the return value from method_missing
    nil # <- suddenly abc is nil, even though abc wasn't touched.
    

    因此,Ruby 看到分配给局部变量 abc 的代码,并决定从那时起 abc 是一个变量,而不是方法调用。

    我相信这样做是为了在没有NoMethodError 的情况下允许这样的事情:

    if something
      a = true
    end
    
    if a
      puts "ah yes, a."
    end
    

    除非你一开始就做傻事,否则很少会碰到这种情况。

    【讨论】:

      【解决方案2】:

      当您分配a = 1 时,您将“覆盖”函数a。我希望这小段代码可以提供帮助:

      def a
        'function a'
      end
      
      p a.class #=> String returned by the function
      a = 1
      p a.class #=> Integer "overridden" by a=1
      p a().class #=> String the function is not lost, needs to be called with round brackets.
      

      【讨论】:

      • 谢谢。这很有帮助。我想补充一点,确定 a 是变量还是方法取决于源代码的使用位置,而不是分配它的执行点。在示例中,当 i = 2 发生在 a 被分配到 else 部分之后。因此,在 if 部分,方法 'a' 被调用。
      • @Vasanth 尝试交换语句的顺序。根据条件if i == 1 向上移动a = 1 etc.
      • @Vasanth:是的,正如您所观察到的,阴影发生在词法上。如果使用是在第一次赋值之前(就源文件中的位置而言),则局部变量不会隐藏先前已知的值
      • @Vasanth 我忘了提到带圆括号的函数调用仍然可用。查看我的编辑。
      【解决方案3】:

      您的示例中没有“本地”内容。在 ruby​​ 中,大多数东西都是可访问的,除非它们是在类或模块定义中定义的,它们可以被“本地化”。以下是编写简单类的方法

      class Foo
        def self.a
          'a'
        end
      end
      

      这里我们只定义了一个类方法,它总是返回字符串a,它不能被修改。如果要封装,建议不要写没有它的东西。否则,您几乎可以在 Ruby 中的任何地方修改任何内容,这就是为什么它是元编程的好语言。对于其他想法也许have a look here

      【讨论】:

        猜你喜欢
        • 2016-11-21
        • 2016-02-01
        • 2010-09-15
        • 2012-02-26
        • 1970-01-01
        • 1970-01-01
        • 2015-11-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多