【问题标题】:Ruby: export variable into local namespaceRuby:将变量导出到本地命名空间
【发布时间】:2011-10-24 14:46:36
【问题描述】:

我想以编程方式将一个新变量插入到本地 Ruby 命名空间中。比如我希望能写

label = 'some_name'
# some code equivalent to
#   some_name = 3
# but using only 'label' to get the name.
puts some_name  # returns 3

我在中间放什么来完成这项工作?

【问题讨论】:

  • 当你说符号时,我猜你指的不是 Ruby 中的符号,对吧(例如 :a_symbol)?如果在后面的代码行中没有使用标签,它到底是什么?
  • @mikong:谢谢,我已经澄清了这个问题。我希望 some_name 稍后在代码中可用。您可以假设label 只是一种知道如何调用变量的机制。
  • 起初我认为你应该只使用 Ruby 常量。但是看起来你想随意更改标签,而你的 puts 行可以更改为新名称,对吗?等你确认后我会写解决方案。
  • 你真的应该只使用哈希。乱用 eval 会让你的代码更丑陋、更慢、更不习惯和更容易出错。
  • @Chuck:通常这将是一种可怕的做法,是的 - 但是,在这种特殊情况下,我想为需要这样设置的用户支持某种 DSL。它肯定不会被用作通用编程技术:)

标签: ruby reflection metaprogramming


【解决方案1】:

我已经回答了另一个 SO question similar to this。简短的回答是,如果您特别想根据另一个变量的值创建一个具有其名称的局部变量,那么就没有办法做到这一点。如果您只是想让 看起来 就好像您已经创建了一个本地但它确实是红宝石魔法,那么像@mikong 的答案是一种方法。

请注意,如果您放松约束并乐于创建实例变量,那么您可以这样做。

label = 'some_name'
self.instance_variable_set("#{label}", 3)
puts @some_name

您甚至可以动态定义一个访问器,然后您可以摆脱难看的@,但是您将再次简单地拥有一个伪装成本地变量而不是真正的本地变量的方法。

【讨论】:

  • +1 用于动态定义的attr_reader。这让我可以实现我的目标。
【解决方案2】:

以下不是您上面提到的两行之间的代码:

class Example
  attr_accessor :label

  def method_missing(name, *args, &block)
    return some_processing  if name == label.to_sym
  end

  def some_processing
    3 # of course, this can be something more complicated
  end

  def test
    @label = 'some_name'
    puts some_name
  end

end

尽管如此,它似乎可以满足您的需求。该机制已与您提供的不同(标签现在是一个属性)。此外,从技术上讲,它不是一个变量,而是一个具有动态名称的方法,可以返回您需要的内容。

就个人而言,我认为您的要求似乎有点危险,因为“变量”名称发生了变化。我可能不会在我的示例中使用代码。我想根据项目要求,我会想出不同的方法。

【讨论】:

    【解决方案3】:
    label = 'some_name'
    eval "#{label} = 3"
    puts eval "#{label}"
    puts local_variables
    

    请注意,您可能永远没有机会执行...

    puts some_name
    

    ...因为如果您知道要创建哪些局部变量,则无需使用运行时代码命名它们。这很好,因为解释器将无法直接puts some_name,因为它从未解析 some_name 的赋值。但它那里,而且它本地的,正如puts local_variables 能够显示的那样。

    【讨论】:

    • 有趣。您的所有四行代码都在 ruby​​-1.8.7-p334 中为我工作。但是,如果我在 ruby​​-1.9.2-p180 中运行相同的程序,则puts local_variables 仅输出“标签”,puts eval "#{label} 会引发异常:test.rb:3:in 'eval': undefined local variable or method 'some_name' for main:Object (NameError)
    • 这是因为在 1.9 中,局部变量仅在定义它们的 eval 的上下文中可用。所以你在一个eval 中定义一个本地并尝试在另一个中使用它,你会得到......好吧,正是你得到的:)。
    • 嗯。因此,切换到创建实例变量而不是本地变量可能是一个好主意,或者首先使用更复杂的数据结构,这样您就不需要动态创建单个名称。很难看出通过简单的 Hash 键创建 Ruby 级名称的好处。 (我尽量避免给出“一开始就不要那样做”的建议,因为有时动机是学术好奇心。但在这种情况下......)
    猜你喜欢
    • 2023-03-11
    • 1970-01-01
    • 2016-12-03
    • 2018-05-06
    • 1970-01-01
    • 2011-01-25
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多