eval, class_eval, instance_eval和binding
前些天写html生成器的时候用到了erb,在生成html的时候是这么一句:
html=tpl.result(binding) |
binding这个变量(Kernel的一个方法 T_T)有点古怪,就搜了下。它表示了ruby的当前作用域,没有任何对外可见的成员函数,唯一的用途就是传递给eval作第二个参数。因而可以这样:
def test_binding magic= 'brother Chun is PURE MAN' return binding end eval "puts magic" , test_binding |
这样就穿越了一个作用域。
有时可以见到这样的构造函数:
a=Baby. new { name "Makr" father "Mike" age 0 . 2 } a.cry |
好处就是好看。实现起来其实也很容易,用instance_eval:
class Baby def initialize(&blc) instance_eval(&blc) #here end def name(str= nil ) @name =str if str @name end def age(num= nil ) @age =num if num @age end def father(str= nil ) @father =str if str @father end def cry puts "#{name} is only #{age.to_s} year old, he wanna milk! Brother Chun is PURE MAN!" end end |
有重复代码?用class_eval缩短之,有点像宏了:
class Baby def initialize(&blc) instance_eval(&blc) end def Baby.my_attr(*names) names. each {|n| class_eval %{ def #{n}(x=nil) @ #{n}=x if x @ #{n} end } } end my_attr :name , :father , :age def cry puts "#{name} is only #{age.to_s} year old, he wanna milk! Brother Chun is PURE MAN!" end end a=Baby. new { name "Makr" father "Mike" age 0 . 2 } a.cry |
这里class_eval穿越到了类的作用域,实现了动态添加函数。instance_eval也是,穿越到了实例的作用域,实现修改其内部数据。明白了它们的穿越关系,我们可以实现自己的class_eval和instance_eval——从合适的地方搞到binding就行了。
class Baby def my_instance_eval(code) eval code, binding end def Baby.my_class_eval(code= '' ) eval code, binding end end |
就这么简单。调用的时候就像这样:
class Baby def initialize(code) my_instance_eval(code) end my_attr :name , :father , :age end a=Baby. new %{ name "Test" father "Orz" age 0 . 2 } |
刚才省略了一点,那就是class_eval和instance_eval可以接受block代替字符串。搜了下,貌似没找到eval接受block的方法,所以这顶多算是只能eval字符串的山寨class_eval。
update: 想起来ruby中lambda和proc在作用域上的小区别,也就是binding的不同了。proc直接使用原先的binding,lambda继承原先作用域创建一个新的binding。
如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码


机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
2009-08-28 javascript Array对象