Ruby: 变量名内嵌字符串

5
在Ruby中,我如何插值字符串以创建变量名?
我希望能够这样设置一个变量:
"post_#{id}" = true

这会返回一个语法错误,有趣的是:
syntax error, unexpected '=', expecting keyword_end

通常而言,这种需求是一种代码异味,表明数据结构的选择不佳。与其使用单独的变量post_1post_2post_N,最好的选择(在各个方面上)是使用哈希表,例如:post = { 1 => true, 2 => true, ...} - Sergio Tulentsev
@Jörg,OP并没有询问如何动态创建本地变量。他/她可能只想知道如何动态获取或设置现有的本地变量。 - Cary Swoveland
2个回答

6

我相信你可以做类似以下的事情:

  send("post_#{id}=", true)

当然,这将需要您拥有适当的setter/getter。但是,由于您正在动态执行此操作,所以可能没有这些内容。
因此,您可以尝试以下方法:
  instance_variable_set("@post_#{id}",true)

获取变量的值:

  instance_variable_get("@post_#{id}")

顺便说一下,如果你厌倦了输入instance_variable_set("@post_#{id}",true),那么可以尝试一些有趣的方法,比如:

class Foo

  def dynamic_accessor(name) 
    class_eval do 
      define_method "#{name}" do
        instance_variable_get("@#{name}")
      end
      define_method "#{name}=" do |val|
        instance_variable_set("@#{name}",val)
      end
    end
  end

end

在这种情况下,你可以:
2.3.1 :017 > id = 2
 => 2 
2.3.1 :018 > f = Foo.new
 => #<Foo:0x00000005436f20> 
2.3.1 :019 > f.dynamic_accessor("post_#{id}")
 => :post_2= 
2.3.1 :020 > f.send("post_#{id}=", true)
 => true 
2.3.1 :021 > f.send("post_#{id}")
 => true 
2.3.1 :022 > f.send("post_#{id}=", "bar")
 => "bar" 
2.3.1 :023 > f.send("post_#{id}")
 => "bar" 

是的,send已经过时了,instance_variable_set很好用。虽然需要在变量名前加上@前缀,但这很容易解决,而且考虑到函数名称,这也是完全合理的。谢谢! - t56k

0

这涉及到获取和设置本地变量。假设

id = 1
s = "post_#{id}"
  #=> "post_1"

自 Ruby v1.8 以来,不再支持动态创建本地变量。因此,如果本地变量 post_1 不存在,则唯一创建它的方法是使用赋值语句:
post_1 = false

如果本地变量post_1存在,您可以使用以下代码动态检索其值:
b = binding
b.local_variable_get(s)
  #=> false

(或者b.local_variable_get(s.to_sym)) 并使用动态方式设置其值。

b.local_variable_set(s, true)
  #=> true
post_1
  #=> true

(或者b.local_variable_set(s.to_sym, true))。

请参见Binding#local_variable_getBinding#local_variable_set


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接