新手问题 如何获取 local variable 的名字

physaris · 2015年08月30日 · 最后由 mueven 回复于 2015年09月07日 · 2077 次阅读

各位好,在网上搜了好久没找到方法,求助一下本坛。

var1 = 1

def func(params)
  #将var1作为参数传入func,怎么获取到var1的变量名即"var1"
end

func(var1)

你传入的其实是 1。

关注一下

你这种情况不应该传 Hash 吗?

因为 Ruby 没办法监听 local_variable 的赋值行为,所以原则上是无解的

但是有一些黑科技。。 打个比方你可以分析源代码里对这个函数的调用,把参数拿出来

var1 = 1

def func(params)
  line_num = caller[0].match(/#{$0}:(\d+):/)[1].to_i
  param_name = File.open($0).readlines[line_num-1].match(/func\((.+)\)/)[1]
end

p func(var1)  # => "var1"

大概就是这样,其实取参数用这个正则肯定不行。。但是我不会写正则,就糊弄一下


还有一种方法是看参数的 object_id 或地址,因为 Ruby 传参都是传引用 比对一下 local_variables 的 object_id 就好了,但是在方法内拿外面的 binding 是很麻烦的。。而且有同值不同变量名的话也会 GG

也举一个例子

var1 = 1

$bindings = {}
set_trace_func proc{|*e| $bindings[e[2]] = e[4] if e[0] == "line"}

def func(params)
  line_num = caller[0].match(/#{$0}:(\d+):/)[1].to_i
  params_binding = $bindings[line_num]
  param_name = params_binding.eval("local_variables").first{|x| params_binding.eval("#{x}.object_id") == params.object_id }
end

p func(var1)  # => :var1

不过这种不可控的 set_trace_func 会严重拖慢程序的执行

感谢以上各位的回复。 #5 楼 @cicholgricenchos 非常感谢你如此详细的回复,确实有点黑科技,也许还有些更加黑科技的我们目前还没接触到(这也是 Ruby 吸引我,吸引大家的地方),相信是有解决方案的。 :plus1:

@cicholgricenchos 的想法很不错,赞一个!

提个可能相关的事情, 如果你的程序需要辨别获取这个东西, 那你需要考虑一下是不是设计方面有什么问题. 参见 Tell, Don't ask . 当然如果仅仅是好奇语法就当我没说..

当进入 func 方法时,已经切换了作用域。对于在 func 中,var1 已经不是 local_variable,var1 已经失效。 所以在 func 中输出 var1,只能用其它方法#5。 #5 里面,第二个方法,使用了binding, set_trace_func, 然后用 proc 将当时的 bangding 带入了 方法 func 中,所以 var1 才可以见。

#8 同意 8 楼的说法.....

需要 登录 后方可回复, 如果你还没有账号请 注册新账号