【问题标题】:Ruby: getting variable name [duplicate]Ruby:获取变量名[重复]
【发布时间】:2013-03-26 13:39:12
【问题描述】:

如何获取变量名?例如,

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;

【问题讨论】:

  • stackoverflow.com/questions/1356749 这更接近你的要求。
  • 另一个用例是使用变量名作为哈希键,例如 es 例如:a=1; b=2; h=Hash[a,b]; puts h 应该是:{a: 1, b: 2}

标签: ruby


【解决方案1】:

你需要跨越当前变量范围的绑定,你用the Binding class做的:

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(),它会在该上下文中计算变量。

【讨论】:

    【解决方案2】:

    首先,您不能实现puti 并直接调用puti a_var 以获得a_var = value of a_var 的输出。在puti 的主体部分,Ruby 只能看到puti 的形参名,无法推断出实参名。

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

    但是,您可以在Continuation 的帮助下实现put :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解释器将立即终止并且跟踪函数没有机会运行。这就是最后一个“占位符”行的重点。

    【讨论】:

    • 它很老套,但我喜欢这个。谢谢;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-02
    • 2013-09-11
    • 2017-08-25
    • 2012-04-05
    • 2013-07-16
    相关资源
    最近更新 更多