`
azure_sky
  • 浏览: 12530 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

一点点不同 module_eval, instance method, singleton method

阅读更多
这个标题比较怪,实际上很简单,看下列代码
ruby 代码
 
  1. class Test  
  2.     class <<self  
  3.         def add_method_a  
  4.             module_eval %{  
  5.                 def method_a  
  6.                 end  
  7.             }  
  8.         end  
  9.     end  
  10.       
  11.     add_method_a  
  12. end  
  13.   
  14. puts Test.new.respond_to?(:method_a)  
运行结果是打印出 true, 不知道会不会有人和我有一样的疑问,为什么在singleton方法add_method_a中调用module_eval 定义动态方法的结果是为Test类增加了一个instance method而不是一个singleton method。
其实,解释很简单,原因就在于,ruby解释过程中instance method和singleton method处理方式的一点不同:
cpp 代码
 
  1. // singleton method的解释过程    
  2. case NODE_DEFS:    
  3.     VALUE klass;    
  4.     // ... ...    
  5.     klass = rb_singleton_class(recv);    
  6.     // ... ...    
  7.     rb_add_method(klass, node->nd_mid, defn,    
  8.               NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));   
cpp 代码
 
  1. // eval.c    
  2. VALUE ruby_class;    
  3. // ... ...    
  4. // 普通method的处理方式    
  5. case NODE_DEFN:    
  6.     // ... ....    
  7.     rb_add_method(ruby_class, node->nd_mid, defn, noex);   
虽然,两者同样使用rb_add_method添加method,但前者使用局部变量klass,而后者使用的是全局变量ruby_class。
ruby_class 是ruby解释过程中栈信息的一部分,用来记录当前语句(Node)所在的类范围,很明显,例子中module_eval执行时,ruby_class指向的仍然是Test类,因此,运行的结果是我们为Test添加了一个instance method。
对此,我们可以略微加以证明,在上面两处调用rb_add_method的地方加上一条打印信息:
cpp 代码
 
  1. printf("curren class: %s method: %s\n", rb_class2name(ruby_class), rb_id2name(node->nd_mid));    

编译ruby,再次运行样例代码, 结果很清楚的告诉我们,此时ruby_class指向的都是Test类。
写倒这里,我们也顺带证明了一下一个我们常用的小技巧:
ruby 代码
 
  1. // 例如我们自己的"attr_accessor"
  2. module MyAttribute  
  3.     def add_attribute name  
  4.         module_eval %{  
  5.             def #{name}  
  6.                 @#{name}  
  7.             end  
  8.               
  9.             def #{name}= value  
  10.                 @#{name} = value  
  11.             end  
  12.         }  
  13.     end  
  14. end  
  15.   
  16. class TestModule  
  17.     extend MyAttribute  //增加singleton method add_attribute
  18.     add_attribute :my_attr  
  19. end  
  20.   
  21. require 'date'  
  22. t = TestModule.new  
  23. t.my_attr = Date.today  
  24. puts t.my_attr  

可以方便为我们的类添加一些简单实用的小方法 :)
分享到:
评论

相关推荐

    trec_eval_latest.tar

    本文将深入探讨名为“trec_eval_latest.tar”的压缩包文件,它包含了trec_eval的最新版本——trec_eval.9.0。 trec_eval是TREC官方提供的一个开源命令行工具,主要用于分析和比较信息检索系统的评价指标。该工具...

    Ruby Meta Programming: define_method or class_eval

    my_instance.my_method # 输出 "Hello, World!" ``` 在这个例子中,`define_method`在`MyClass`上定义了一个名为`my_method`的方法,该方法在调用时会打印出"Hello, World!"。 另一方面,`class_eval`接收一个字符...

    reset_jetbrains_eval_windows.rar

    标题 "reset_jetbrains_eval_windows.rar" 暗示这是一个针对JetBrains开发的IDE在Windows操作系统上的试用重置工具。JetBrains是一家知名软件开发公司,以其高效、功能强大的集成开发环境(IDE)如IntelliJ IDEA、...

    GD32F450I_EVAL官方评估板 _LittlevGL代码移植

    在本文中,我们将深入探讨如何将LittlevGL图形库移植到GD32F450I_EVAL官方评估板上。...在GD32F450I_EVAL_LittlevGL压缩包文件中,应包含移植所需的所有源代码、配置文件和示例,帮助开发者顺利进行移植工作。

    I2C.zip_STM3210E_STM32F10X.h_stm32_eval.h_stm32_eval_i2c__stm32f

    #include "stm32_eval_i2c_tsensor.h" #include "stm32_eval.h" #ifdef USE_STM32100E_EVAL #include "stm32100e_eval_lcd.h" #elif defined USE_STM3210E_EVAL #include "stm3210e_eval_lcd.h" #elif defined ...

    license_eval_halcon_progress_2022_03.dat

    license_eval_halcon_progress_2022_03.dat

    STM3210C_EVAL_stm32_STM3210C_EVAL_temperature565_

    在给定的标题"STM3210C_EVAL_stm32_STM3210C_EVAL_temperature565_"中,我们可以推测这是与STM3210C EVAL板相关的项目或者固件更新,可能包含了针对STM3210C处理器的温度测量或控制功能。"temperature565"可能指的是...

    j4locr_eval

    标题“j4locr_eval”指向的是一个与Java开发相关的技术或库,特别是与图像处理或者文本识别有关,因为“j4locr”通常与OCR(Optical Character Recognition,光学字符识别)技术关联。这个“eval”可能表示这是评估...

    reset_jetbrains_eval_windows.vbs

    可以无限重置

    CrystalC_REVS_ProPlus_Eval_v480.Zip

    其中,“CrystalC_REVS_ProPlus_Eval_v480”是一款备受关注的软件,它能够帮助程序员快速地将代码逻辑转化为直观的流程图,从而增强代码的可读性和可维护性。本文将深入探讨这款工具的功能特性、使用方法以及其在...

    Faster R-CNN中voc_eval.py文件

    借助Faster R-CNN中voc_eval.py文件,测试YOLO测试数据集mAP等结果,博客见

    trec_eval.exe

    trec_eval.exe是一款广泛应用于信息检索领域的效果评价工具,它是由TREC(Text REtrieval Conference)组织开发的,旨在为研究人员提供一种标准化的方式来评估和比较不同的信息检索系统。TREC是国际上颇具影响力的...

    license_eval_halcon_steady_2021_07.dat等多个文件.rar

    标题中的"license_eval_halcon_steady_2021_07.dat"是一个与HALCON软件相关的许可评估文件。HALCON是MVTec公司开发的一款广泛应用的机器视觉软件,它提供了全面的图像处理功能,包括形状匹配、模板匹配、1D/2D码识别...

    GD32E103C_EVAL.rar

    GD32E103C_EVAL.rar 是一个针对GD32E103微控制器的资源包,它包含了多个流行的实时操作系统(RTOS)的移植版本,包括FreeRTOS、RT-Thread、ucos_ii、ucosiii以及RTX和LiteOS。这些RTOS的移植为开发者提供了在GD32...

    GD32E230C_EVAL.rar

    标题中的"GD32E230C_EVAL.rar"是一个压缩包文件,主要涉及的是GD32系列微控制器,特别是GD32E230C评估板上的固件移植示例。GD32是由国内知名半导体公司GigaDevice(兆易创新)推出的32位通用MCU产品线,其E230系列...

    GD32107C_EVAL LiteOS FreeRTOS_key uCOS_III_key RTOS Demo源代码.zip

    该压缩包文件包含了一系列关于GD32107C_EVAL开发板上运行的不同实时操作系统(RTOS)的Demo源代码,这些RTOS包括LiteOS、FreeRTOS、uCOS_III和RT-Thread,以及相关的库文件。这里我们将深入探讨这些RTOS及其在GD...

    reset_eval.rar

    标题“reset_eval.rar”暗示了这是一个包含重置评估工具的压缩文件,可能是为了帮助用户恢复注册表到初始状态或者清除特定软件的残留设置。该压缩包可能包含针对Windows和Linux两个不同操作系统的脚本,因为这两个...

    详解Ruby中的instance_eval方法及其与class_eval的对比

    这个BasicObject#instance_eval有点类似JS中的bind方法,不同的时,bind是将this传入到对象中,而instance_eval则是将代码块(上下文探针Context Probe)传入到指定的对象中,一个是传对象,一个是传执行体。...

    license_eval_halcon_steady_2021_08.rar

    标题中的"license_eval_halcon_steady_2021_08.rar"指的是一个用于评估的Halcon软件许可证文件,该文件是2021年8月版本的压缩包。Halcon是一款由德国MVTec公司开发的高级机器视觉软件,广泛应用于工业自动化、质量...

Global site tag (gtag.js) - Google Analytics