首先,您不能实现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 解释器将立即终止并且跟踪函数没有机会运行。这就是最后一个“占位符”行的重点。