如何在Ruby中动态创建全局与局部变量 实现JSON对象转可用变量
Ruby 动态将JSON转换为全局/实例变量实现方案
原代码存在的问题
- 方法调用逻辑错误:
send(eval("#{k}=",v))写法完全不符合API规范,send方法第一个参数需要传入方法名(字符串/符号),后续才是参数值,嵌套eval的写法会直接抛出语法错误。 - 变量类型处理不匹配:
attr_accessor定义的是单例类的实例属性,只能处理不带$前缀的普通变量,无法识别JSON中带$前缀的全局变量。 - 对局部变量的实现逻辑认知错误:Ruby的局部变量是在语法解析阶段就确定的,无法在运行时动态给当前作用域新增可直接调用的局部变量,需求中的「局部变量」只能通过绑定到
binding对象、或者转为实例变量的方式实现。
正确实现方案
我们会区分JSON key是否带$前缀,分别处理为全局变量和当前上下文的实例变量,代码如下:
require 'json' json_str = '{"$a":5,"b":10}' data = JSON.parse(json_str) data.each do |key, value| if key.start_with?('$') # 处理全局变量,用inspect保证值类型正确 eval("#{key} = #{value.inspect}") else # 处理为实例变量,同时定义访问方法,支持直接调用变量名 instance_variable_set("@#{key}", value) define_singleton_method(key) { instance_variable_get("@#{key}") } define_singleton_method("#{key}=") { |new_val| instance_variable_set("@#{key}", new_val) } end end # 测试输出 puts $a puts b
运行输出结果:
5 10
如果需要模拟局部变量的效果,可以通过binding对象操作:
b = binding data.each do |key, value| next if key.start_with?('$') b.local_variable_set(key, value) end # 只能通过binding对象访问动态添加的局部变量 puts b.local_variable_get('b')
注意:通过local_variable_set添加的变量无法直接在当前作用域直接调用变量名,只能通过binding对象的local_variable_get获取,因为Ruby语法解析阶段不会识别运行时新增的局部变量。
内容的提问来源于stack exchange,提问作者Bharath
相关产品推荐
相关产品推荐

