10

如何获得变量名?例如,

def get_var_name(var)
  # return variable name
end

myname = nil
get_var_name myname #=> myname

初始目的:

somevar = "value"

puti somevar #=> somevar = "value"
# that is a shortage for
# `puts "somevar = #{somevar.inspect}"`

我的尝试:

def puti(symb)
  var_name  = symb.to_s
  var_value = eval(var_name)
  puts "#{var_name} = #{var_value.inspect}"
end
puti :@somevar # that actually will work only with class vars or whatever considering var scope;
4

2 回答 2

8

您需要跨越当前变量范围的绑定,您可以使用Binding 类

def puti(symb, the_binding)
  var_name  = symb.to_s
  var_value = eval(var_name, the_binding)
  puts "#{var_name} = #{var_value.inspect}"
end

somevar = 3

puti :somevar, binding   # Call the binding() method

   #=> outputs "somevar = 3"

binding()方法提供一个 Binding 对象,该对象记住调用该方法时的上下文。然后将绑定传递给eval(),它会在该上下文中评估变量。

于 2013-03-26T14:03:20.173 回答
2

首先,您不能实现puti直接调用puti a_var来获取输出为a_var = value of a_var. 在 的主体中puti,Ruby 只能看到 的形参名称puti,无法推断出实际的参数名称。

在 C/C++ 等其他语言中,您可以使用来实现您的puti. 那是另一个故事。

但是,您可以在Continuationput :a_var的帮助下实施。在另一个问题“ Can you eval code in the context of a caller in Ruby? ”中,Sony Santos提供了一个caller_binding实现来获取调用者的绑定(类似于 perl 调用者函数)。

应该稍微改变实现,因为callcc在第一次返回时返回块的返回值。所以你会得到一个Continuation而不是的实例nil。这是更新的版本:

require 'continuation' if RUBY_VERSION >= '1.9.0'

def caller_binding
  cc = nil     # must be present to work within lambda
  count = 0    # counter of returns

  set_trace_func lambda { |event, file, lineno, id, binding, klass|
    # First return gets to the caller of this method
    # (which already know its own binding).
    # Second return gets to the caller of the caller.
    # That's we want!
    if count == 2
      set_trace_func nil
      # Will return the binding to the callcc below.
      cc.call binding
    elsif event == "return"
      count += 1
    end
  }
  # First time it'll set the cc and return nil to the caller.
  # So it's important to the caller to return again
  # if it gets nil, then we get the second return.
  # Second time it'll return the binding.
  return callcc { |cont| cc = cont; nil }
end

# Example of use:

def puti *vars
  return unless bnd = caller_binding
  vars.each do |s|
    value = eval s.to_s, bnd
    puts "#{s} = #{value.inspect}"
  end
end

a = 1
b = 2
puti :a, :b
e = 1 # place holder...

# => a = 1
#    b = 2

注意puti不应该是程序的最后一条语句,否则 ruby​​ 解释器将立即终止并且跟踪函数没有机会运行。这就是最后一个“占位符”行的重点。

于 2013-03-26T14:43:40.240 回答