如何在Ruby中动态访问和分配字符串值作为字符串名称

时间:2015-01-11 08:04:03

标签: ruby string variable-assignment

在PHP中,我可以通过设置$variable_name = fooecho $$variable_name之类的内容来动态访问变量,然后echo foo的值。但我不清楚如何在Ruby中做到这一点。在PHP中我可以做这样的事情;在数组中分配变量名并迭代它们:

# Set string values.
$value_one = 'a one';
$value_two = 'and a two';
$value_three = 'and a three';

# Set array of variable names.
$process_items_array = array('value_one', 'value_two', 'value_three');

# Roll through the values.
foreach ($process_items_array as $value) {
  $$value = do_something($$value) . '<br />';
}

# A simple function for example’s sake.
function do_something ($value = null) {
  return strtoupper($value);
}

但是在Ruby中,相同的东西是什么?例如,我尝试了这个,没有一个项目按预期工作;请注意,这是在非类结构中使用self.引用所指出的伪代码:

# Set string values.
value_one = 'a one';
value_two = 'and a two';
value_three = 'and a three';

# Set array of variable names.
process_items_array = ['value_one', 'value_two', 'value_three']

# Roll through the values.
process_items_array.each { |value|
  self.send("#{value}").to_sym = do_something value.try(self.send("#{value}").to_sym)
}

# A simple function for example’s sake.
def do_something value
  value = value.try(:strip)
  value = nil if value.blank?
  value.upcase
end

请注意我尝试使用instance_variable_get,[send][2]to_sym;我基本上希望有些东西可行,但似乎没什么用。我应该做什么呢?

3 个答案:

答案 0 :(得分:2)

您可以使用eval

执行此操作
# Set string values.
value_one = 'a one';
value_two = 'and a two';
value_three = 'and a three';

# Set array of variable names.
process_items_array = ['value_one', 'value_two', 'value_three']

# Roll through the values.
process_items_array.each do |variable_name|

  # Output value
  puts eval(variable_name)

  # Reassign variable
  new_value = 'foo'
  eval("#{variable_name} = new_value")
end

正如评论中所说,您可能希望将数据存储在哈希中。此外,您需要动态创建或读取变量的代码非常糟糕。

答案 1 :(得分:1)

更红宝石的方式(所以没有&#34;危险&#34; eval)

# Set string values.
value_one = 'a one';
value_two = 'and a two';
value_three = 'and a three';

# Set array of variable names.
process_items_array = ['value_one', 'value_two', 'value_three']

# Roll through the values.
process_items_array.each do |variable_name|

  # Output value
  puts binding.local_variable_get(variable_name.to_sym)

  # Reassign variable
  binding.local_variable_set(variable_name.to_sym, 'foo')
end

puts value_one, value_two, value_three
# foo
# foo
# foo

答案 2 :(得分:-1)

您可以使用Kernel#binding获取当前的Binding对象,然后使用Binding#local_variable_getBinding#local_variable_set来获取和设置本地变量:

# Set string values.
value_one = 'a one';
value_two = 'and a two';
value_three = 'and a three';

# Set array of variable names.
process_items_array = ['value_one', 'value_two', 'value_three']

# Roll through the values.
process_items_array.each { |value|
  binding.local_variable_set(value.to_sym, do_something(binding.local_variable_get(value).to_sym)
}

# A simple function for example’s sake.
def do_something value
  value = value.try(:strip)
  value = nil if value.blank?
  value.upcase
end

# Show that it works:
p value_one, value_two, value_three
# "A ONE"
# "AND A TWO"
# "AND A THREE"

但是,该代码有点不合时宜:

  • 你不会将两个分号和换行符用作表达式分隔符,只有一个
  • 您可以使用Symbol来表示变量名称,而不是String s
  • 您可以使用do / end代替{ / }进行多行副作用
  • 您不会在变量名称中说明变量引用的对象类型(例如foo_array

您必须在使用之前移动do_something的定义,否则您会获得NoMethodError

为了更容易重复,我删除了对active_support的依赖,因此尝试测试的人不必安装额外的宝石,甚至不需要再现解决方案

这将是一个更惯用的代码版本:

# Set string values.
value_one =   'a one'
value_two =   'and a two'
value_three = 'and a three'

# Set array of variable names.
items_to_process = %i[value_one value_two value_three]

# A simple method for example’s sake.
def do_something(value)
  value.upcase
end

b = binding

# Roll through the values.
items_to_process.each do |var|
  b.local_variable_set(var, do_something(b.local_variable_get(var)))
end

# Show that it works:
p value_one, value_two, value_three
# "A ONE"
# "AND A TWO"
# "AND A THREE"