深入理解 ruby 中的 eval 与 binding
来源:互联网 发布:win域名退出中国 编辑:程序博客网 时间:2024/06/06 10:01
eval(expr[, binding[, fname[, lineno=1]]])
eval 可以把字符串当做代码来执行,并返回结果;第二个参数如果是 Proc 对象或 Binding 对象,将在该对象保存的执行环境(作用域)中对字符串解析执行。
这样,就可以通过binding改变 eval 的执行上下文了!
fname,lineno,这两个参数用于发生异常时跟踪调用栈信息。
示例 1 main 环境
irb(main):001:0> var = "hello ruby"=> "hello ruby"irb(main):002:0> eval("p var")"hello ruby"=> "hello ruby"
此处待执行的字符串 “p var”的运行环境为 main;就好像是直接执行了一条 p var 语句。
当前作用域中,var 为 “hello ruby”。
示例 2 foo 环境
irb(main):006:0> def fooirb(main):007:1> var = "hello foo"irb(main):008:1> eval("p var")irb(main):009:1> end=> nilirb(main):010:0> foo"hello foo"
eval 在函数 foo 中执行,因此 eval 的执行环境也变为 foo,var 的值不再是 “hello ruby”而变为“hello foo”。
示例3 binding
binding 会生成并返回 Binding 对象,该对象包含变量、方法等环境信息,可以作为eval的第二个参数,来执行 eval 的执行环境。
代码的运行是不可能脱离环境的,如果不指定,就默认为当前环境,也就是调用 eval 的地方;如果想要灵活的指定运行环境,就需要使用binding了。
irb(main):011:0> binding=> #<Binding:0x007fd391c545b0>irb(main):012:0> binding=> #<Binding:0x007fd391c492a0>irb(main):013:0> binding=> #<Binding:0x007fd391c3c438>
当调用 binding 时,会返回一个 Binding 对象,每次返回的对象都不同,这个一定要注意。如果想要保存执行环境,多次运行eval的话,一定要使用同一个 Binding 对象。
irb(main):014:0> def bindirb(main):015:1> x = 1irb(main):016:1> bindingirb(main):017:1> end=> nilirb(main):018:0> p eval("x=5", bind)5=> 5irb(main):019:0> p eval("x", bind)1=> 1
上例中,每次调用 bind 函数都会返回一个赞新的 Binding 对象,因此执行环境中的 x 始终都是 1。
irb(main):020:0> fix = bind=> #<Binding:0x007fd391beb010>irb(main):021:0> p eval("x = 5", fix)5=> 5irb(main):022:0> p eval("x", fix)5=> 5
这次,将 bind 返回的 Binding 对象保存,执行的 eval 语句会处在相同的执行环境中,变更的内容会被保存。
实例4 binding Proc
def test_bind(x,y,&p)p “x:#{x},y:#{y}”p p.call x,yreturn bindingendp1 = Proc.new(){|x,y| x+y}p2 = Proc.new(){|x,y| x*y}b1 = test_bind(3,5,&p1)=>x:3,y:5=>8=><Binding:0xxxxxxxxx…>b2 = test_bind(3,5,&p2)=>x:3,y:5=>15=><Binding:-xxxxxxxxx>eval(‘p.call x,y’,b1)=>8eval(‘p.call x,y’,b2)=>15
Binding不仅可以保存环境作用域中的变量和self,还能保存作用域中的 block 对象。
实例5 fname, lineno
irb(main):002:0> def foo irb(main):003:1> x = 1irb(main):004:1> bindingirb(main):005:1> end=> nilirb(main):006:0> eval("1/0", foo)ZeroDivisionError: divided by 0 from (irb):4:in `/' from (irb):4:in `foo' from (irb):6:in `eval' from (irb):6 from /opt/ruby200/bin/irb:12:in `<main>'irb(main):007:0> eval("1/0", foo, "dxxxx", 5)ZeroDivisionError: divided by 0 from dxxxx:5:in `/' from dxxxx:5:in `foo' from (irb):7:in `eval' from (irb):7 from /opt/ruby200/bin/irb:12:in `<main>'
上例中,执行“1/0”会抛出异常,由于 irb 本来就是通过 eval 机制来运行代码的,所以会抛出两个类似的栈信息。
当不指定 fname 和 lineno 时,fname = irb, lineno 就等于binding在irb中的行数!
当指定了特定值时,栈信息会根据参数输出对应的 fname 和 lineno!
- 深入理解 ruby 中的 eval 与 binding
- Ruby中的eval与binding
- 深入理解Ruby语言中的String(1)
- 深入理解 Ruby 中的 instance_eval 和 class_eval
- Ruby中的绑定和eval
- 深入认识javascript中的eval
- ruby eval
- shell中的eval与$(())
- 深入理解 Ruby 关键字 yiald
- 深入理解JAVA中的栈与堆
- 深入理解与应用Hadoop中的MapReduce
- 深入理解与应用Hadoop中的MapReduce
- 深入理解与应用Hadoop中的MapReduce
- 深入理解Java中的类与继承
- 深入认识javascript中的eval函数
- 深入认识javascript中的eval函数
- 深入认识javascript中的eval函数【转载】
- 深入认识javascript中的eval函数
- 轻量级C#网络通信组件StriveEngine —— C/S通信开源demo(附源码)
- 挑战程序竞赛系列(51):4.2 推理与动态规划算法(4)
- 升级 phpStudy 中 MySQL 版本至 5.7.17
- svn分支、主干合并
- HDU 1760 A New Tetris Game
- 深入理解 ruby 中的 eval 与 binding
- 获取多个随机生成的不重复的6位数,不重复的6位数或8位数串
- loj6002网络流 24 题 最小路径覆盖 最大流
- 线程同步(多线程协同使用有限资源)
- iOS 使用ProtocolBuffer 时报 Protocol message end-group tag did not match expected tag.
- JDK+Tomcat搭建JSP运行环境--JSP基础
- 010-logback中过滤器filter
- Kafka日志存储系统和offset查找逻辑
- Vuejs computed get set 计算属性