分类:
2010-07-21 00:05:10
版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://blackanger.blog.51cto.com/140924/87102 |
先看Ruby参考里面对eval和binding的解释: eval(expr[, binding[, fname[, lineno=1]]]) 把字符串expr当作Ruby程序来运行并返回其结果。若给第二参数传递Proc对象或Binding对象的话,将在生成该对象的环境中对字符串进行计算。请参考binding。 def foo a = 1 binding end eval("p a", foo) # => 1 若指定了fname 和 lineno的话,将假定字符串位于fname文件lineno行,并且进行编译。这时可以显示栈跟踪(stack trace)等信息。 binding 生成并返回Binding对象。该对象包含变量、方法等的环境信息,它通常用作Eval的第二参数。 由上面信息不难理解。 eval可以把字符串当作Ruby程序来运行并返回其结果,同时也可以指定该字符串运行的环境, 只需要加第二个参数就行了,把binding的环境传过去。 太cool了。 例子: ruby 1.8.7 (2008-06-20 patchlevel 22) [i686-darwin9.2.1] irb(main):001:0> def foo irb(main):002:1> x = 1 irb(main):003:1> binding irb(main):004:1> end => nil irb(main):005:0> save_binding = foo => # irb(main):006:0> p eval("x", save_binding) 1 irb(main):007:0> x = 2 irb(main):008:0> p eval("x", save_binding) 1 irb(main):009:0> p eval("x = 5 ", save_binding) 5 irb(main):010:0> p eval("x", save_binding) 5 上例中,eval的第一个参数放在第二个参数所形成的环境里被执行,同时第一个参数影响着第二个参数的闭包环境。 irb(main):011:0> def foo(my_binding) irb(main):012:1> eval("x", my_binding) irb(main):013:1> end irb(main):014:0> def bar irb(main):015:1> x = 100 irb(main):016:1> foo(binding) irb(main):017:1> end irb(main):018:0> p bar 100 irb(main):019:0> def foo(my_binding) irb(main):020:1> x = 200 irb(main):021:1> eval("x", my_binding) irb(main):022:1> end irb(main):023:0> p bar 100 上例中x的值已经和bar方法里的x绑定好了,任凭你foo方法如何改变都是无用的。 irb(main):024:0> x = 100 => 100 irb(main):025:0> block_var = lambda{ x } => # irb(main):026:0> def foo(blk) irb(main):027:1> blk.call irb(main):028:1> end irb(main):029:0> p foo(block_var) 100 上例中,lambda对象已经和x = 100 形成了一个闭包。 你 call他的时候当然是得到100. class << Object def xxx(name,klass) define_method( name ) { eval "@#{name} ||= #{klass}.new" } end end class << Object def attr_init(name, klass) eval "define_method(name) { @#{name} ||= #{klass}.new }" end end 这两种写法的区别是:第二种写法只需要调用一次eval方法,而不是在每次进行方法定义时都去重新调用eval。 |