【问题标题】:Variable defined despite condition should prevent it尽管条件定义的变量应该阻止它
【发布时间】:2021-12-06 08:02:45
【问题描述】:

今天我遇到了一段有趣的代码。这更像是一个关于 ruby​​ 解析器的科学问题。 我们知道 ruby​​ 中的一切都是一个对象,每个表达式的计算结果至少为 nil。 但是下面的“赋值”是如何解析的:

somevar
 NameError: undefined local variable or method 'somevar' for main:Object
somevar = "test" if false
 => nil
somevar
 => nil

在赋值中使用之前,您会看到该变量是未定义的。但是由于这种情况,分配没有发生。还是因为条件评估为零而发生?我尝试了一些在这种情况下会损坏的东西,但它确实有效:

a = {}
a[1/0]
 ZeroDivisionError: divided by 0
a[1/0] = "test" if false
 => nil

那么这是否意味着按原样工作?或者在访问之前测试变量(defined?(somevar))是否有意义,以防未来版本的 ruby​​ 会破坏这种行为?例如,将分配的指针保存到该变量。 我目前使用的 ruby​​ 版本是 3.0.2。

【问题讨论】:

    标签: ruby undefined variable-assignment


    【解决方案1】:

    这是 Ruby 中的预期行为。引用自Ruby docs

    局部变量是在解析器遇到赋值时创建的,而不是在赋值发生时创建的:

    a = 0 if false # does not assign to a
    
    p local_variables # prints [:a]
    
    p a # prints nil
    

    【讨论】:

    • 谢谢你:D。真遗憾,我无法在文档中找到这部分。即使有几乎相同的例子:/
    【解决方案2】:

    如果您执行= "test" if false,它的计算结果为nil => 不需要分配。但是通过调用somevar = ...,您告诉解释器声明名称somevarnil 不一样(如果有意义的话)。

    [] 运算符没有声明变量(仅访问),但由于 if false 不正确,因此没有赋值,因此不会评估整个左侧。

    考虑:

    a = [1,2,3]
    a[1] = "test" if false
    a
    => [1,2,3]
    

    a[1] 既不是零也不是测试。

    不确定您的期望或未来 Ruby 将如何打破这一点?

    【讨论】:

    • 我缺少的部分是解释器创建变量的地方。为了解释我认为它将来可能会中断的原因:当你定义这个变量时,内存中有一个从未使用过的引用。这是一个非常小的,仍然可以得到“优化”。但正如 spickermann 指出的那样,这是预期和记录的行为。所以我可以节省地使用它:D
    猜你喜欢
    • 2017-03-04
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    • 1970-01-01
    • 2020-09-20
    相关资源
    最近更新 更多