Ruby 突然发现 Ruby 好像没有 global_variable_get/set 方法?

ibachue · 2013年05月13日 · 最后由 seiran 回复于 2013年05月17日 · 4592 次阅读

RT 貌似只有 global_variables 定义在 Kernel 里 是不是啊。。。

global variables 全局可见, 搞那两个方法多于吧。

#1 楼 @zgm 关键是如果我要实现所有 global variables 打印的功能 我不得不用 eval 取值了。。 那太 evil 了。。

可以的...

require 'rbconfig'
require 'fiddle'
libruby = Fiddle.dlopen RbConfig::CONFIG['libdir'] + '/' + RbConfig::CONFIG['LIBRUBY_SO']
rb_gv_get = Fiddle::Function.new libruby['rb_gv_get'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP
$x = 3
$y = 'a'
puts rb_gv_get.('$x').to_value
puts rb_gv_get.('$y').to_value

另外注意要先转成字符串, 不接受 symbol 参数

#4 楼 @luikore 大神的答案经常这么不同凡响。

#5 楼 @zgm #6 楼 @iBachue

只是碰巧知道 rb_gv_get 这个函数 (ruby hacking guide) 和 fiddle 的用法罢了...

#7 楼 @luikore 大神就是总能碰巧知道...

#2 楼 @iBachue local_variables 的取法才 evil…… 单纯 global_variables 还好…… (不过也没有检测变量名)

def gv_get(a)
  eval a.to_s
end

def gv_set(a, b)
  eval "#{a}=b"
end

def lv_get(a, binding = nil, &block)
  eval a.to_s, binding || block.binding
end

def lv_set(a, b, binding = nil, &block)
  eval "#{a}=ObjectSpace._id2ref(#{b.object_id})", binding || block.binding
end



gv_set(:$a, 3)
gv_get(:$a)

a = 3
p lv_get(:a){}
lv_set(:a, 5){}
p a

r = lambda{
  a = 3
  b = 5
  binding
}.call

p lv_get(:a, r) + lv_get(:b, r)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册