Ruby将散列内的值转换为局部变量

时间:2012-11-14 15:49:54

标签: ruby

说我有这个哈希:

entry = {"director"=>"Chris Nolan", "prducer"=>"Sum Duk", "writer"=>"Saad Bakk"}

我想将每个键提取到自己的局部变量中,并带有相关的值:

director = "Chris Nolan"
producer = "Sum Duk"
...

使用循环而不是:

director = entry["director"]

由于有很多值,我不想单独进行。

我发现这几乎完全有效,除了它创建了一个实例变量,我想要一个局部变量,但local_variable_set由于某种原因不存在。

entry.each_pair { |k, v| instance_variable_set("@#{k}", v) }

有解决方案吗?或者失败了,一种将实例变量转换为本地变量并删除实例变量而不逐一执行的方法?

4 个答案:

答案 0 :(得分:6)

选项1

除了有趣之外,我不能推荐这个,但它主要有你想要的效果:

entry.each |k, v|
  singleton_class.send(:attr_accessor, k)
  send("#{k}=", v)
end

director                        # => "Chris Nolan"
self.director = "Wes Anderson"  # Unfortunately, must use self for assignment
director                        # => "Wes Anderson"

它不是创建局部变量,而是在当前对象的单例类上定义acccessor方法,您可以将它们称为局部变量。

让他们更多"本地"完成后,您可以使用singleton_class.remove_method删除这些方法。您甚至可以尝试使用相同的名称对任何现有的单例类方法进行别名,然后将其还原。

选项2

这是我在实际代码中使用的东西。它需要随Ruby On Rails一起提供的ActiveSupport gem,但也可以单独使用。

director, producer, writer = entry.values_at('director', 'producer', 'writer')

不幸的是,它需要输入两次变量名,而不是你要求的零次。如果您确定散列中值的顺序,可以写:

director, producer, writer = entry.values  # Not so good, IMO.

我对这个版本感到不安,因为现在创建哈希的代码没有明确的责任来确保哈希按照特定的顺序。

注意

如果您的目标只是减少输入,那么这种方法每个变量访问只需要两个字符,而不是真正的局部变量:

e = OpenStruct.new(entry)
e.director     # => "Chris Nolan"

答案 1 :(得分:4)

您可以使用eval执行此操作,但对这些变量的所有操作必须在其定义的范围内。

例如,这将起作用:

vals = {
  "foo" => "bar",
  "baz" => "qux"
}

eval <<-EOF
  #{ vals.map {|k, v| "#{k} = \"#{v}\""}.join("\n") }
  puts foo
EOF

然而,这不会:

vals = {
  "foo" => "bar",
  "baz" => "qux"
}

eval <<-EOF
  #{ vals.map {|k, v| "#{k} = \"#{v}\""}.join("\n") }
EOF

puts foo

因为foo在评估结束时超出了范围。但是,如果所有关于变量的工作都可以在eval的范围内完成,那么它是非常可行的。

答案 2 :(得分:2)

由于范围可变,您无法创建局部变量 如果在块内创建局部变量,则该变量只能在块本身内部访问 有关详细信息,请参阅此问题 Dynamically set local variables in Ruby

答案 3 :(得分:0)

扩展@antinome的注释:如果您希望局部变量存在,因为您想通过例如将它们内插到字符串中来动态访问它们,那么OpenStruct + instance_eval提供了以下内容: / p>

require 'ostruct'
OpenStruct.new(entry).instance_eval("Directed by #{director}, produced by #{producer}")