2013-03-26 177 views
8

如何獲取變量名稱?例如,Ruby:獲取變量名稱

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; 
+0

http://stackoverflow.com/questions/1356749這更接近您的要求。 – 2013-03-26 13:52:43

回答

2

首先,您不能執行puti並直接調用puti a_var以獲得輸出爲a_var = value of a_var。在puti的主體上,Ruby只看到puti的形式參數名稱,它不能推斷出實際的參數名稱。

在其他語言如C/C++中,您可以使用Macro來實現您的puti。這是另一個故事。

但是,可以實現put :a_var,與Continuation幫助。在另一個問題「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解釋器將立即終止與跟蹤功能就沒有機會跑。所以這就是最後一個「佔位符」線的重點。

+0

這是哈克,但我喜歡這一個。謝謝; – ted 2013-03-27 14:33:27

8

您需要跨當前變量的作用域的結合,你有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(),並在該上下文中評估該變量。