如何在 Ruby 中动态访问和分配字符串值作为字符串名称
How to access and assign a string value as a string name dynamically in Ruby
在 PHP 中,我可以通过设置类似 $variable_name = foo
和 echo $$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 中,什么是等效的?例如,我已经尝试过这个并且 none 的项目按预期工作;请注意,这是通过在非 class 结构中使用 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]
and to_sym
;我基本上希望有些东西会起作用,但似乎什么都不起作用。我应该怎么做?
你可以用 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
正如评论中所说,您可能希望将数据存储在哈希中。此外,您需要动态创建或读取变量的代码闻起来真的很糟糕。
更 ruby 的方式(所以没有 "dangerous" 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
您可以使用Kernel#binding
to get the current Binding
object and then Binding#local_variable_get
and Binding#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
s 来表示变量名称,而不是 String
s
- 对于多行副作用块,您将使用
do
/end
而不是 {
/}
- 您不会在变量名中声明变量引用的对象的类型(例如
foo_array
)
你还必须在使用之前将 do_something
的定义向上移动,否则你会得到 NoMethodError
.
为了更容易重现,我删除了对 active_support
的依赖,这样尝试测试它的人就不必安装额外的 gem,它甚至不需要重现解决方案。
这将是代码的更惯用版本:
# 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"
在 PHP 中,我可以通过设置类似 $variable_name = foo
和 echo $$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 中,什么是等效的?例如,我已经尝试过这个并且 none 的项目按预期工作;请注意,这是通过在非 class 结构中使用 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]
and to_sym
;我基本上希望有些东西会起作用,但似乎什么都不起作用。我应该怎么做?
你可以用 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
正如评论中所说,您可能希望将数据存储在哈希中。此外,您需要动态创建或读取变量的代码闻起来真的很糟糕。
更 ruby 的方式(所以没有 "dangerous" 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
您可以使用Kernel#binding
to get the current Binding
object and then Binding#local_variable_get
and Binding#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
s 来表示变量名称,而不是String
s - 对于多行副作用块,您将使用
do
/end
而不是{
/}
- 您不会在变量名中声明变量引用的对象的类型(例如
foo_array
)
你还必须在使用之前将 do_something
的定义向上移动,否则你会得到 NoMethodError
.
为了更容易重现,我删除了对 active_support
的依赖,这样尝试测试它的人就不必安装额外的 gem,它甚至不需要重现解决方案。
这将是代码的更惯用版本:
# 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"