我在C中编写了一个简单的Stacks和Queues library作为Ruby的扩展,并且每当我需要检索一个代码时,都需要编写相同的两行代码实例变量(在本例中为stack.h
):
VALUE stack;
stack = rb_iv_get(self, "@stack");
从我发现的情况来看,与实际的Ruby代码相比,这种方法相当慢(多达0.1秒)而且根本不是DRY。有什么办法可以把它提取出来,用于某种全局变量或函数吗?我尝试将这两行放在任何函数之外但我需要使用rb_iv_get(self, "@iv_name")
访问self,这样就会抛出错误。
答案 0 :(得分:1)
我不认为您的速度问题与调用rb_iv_get
直接相关。您应首先考虑是否需要将数据保存在Ruby对象中。将数据放在C数据结构中,并根据扩展添加到类中的方法将其转换为Ruby数据或从Ruby数据转换为更有效。
但是,如果您需要将Ruby对象作为C扩展的一个组成部分进行管理,那么您可以将该值保留为C struct
的一部分,并为Ruby方实现一个访问器,以便查看它必要。然后,您根本无需致电rb_iv_get
即可访问C中的VALUE
。
首先,您需要了解如何使用ruby.h中的Data_Wrap_Struct
和Data_Get_Struct
宏 - 使用CD Jukebox示例Extending Ruby chapter of Programming Ruby是查看此操作的好地方
然后,有了这个,你可以使你的一个结构组件成为一个值:
typedef struct my_structure {
int some_number;
VALUE some_ruby_val;
} MyStructure;
除了CD Jukebox示例之外,您还需要实现一个将some_ruby_val
标记为正在使用的函数(如果您不这样做,Ruby的垃圾收集器将回收内存,您可以结束指向其他一些对象 - 通常会让你产生段错误:
void my_structure_gc_mark( MyStructure *mine ) {
rb_gc_mark( mine->some_ruby_val );
return;
}
当你使用Data_Wrap_Struct
时,你会告诉它关于这个函数,以及链接中记录的destroy函数:
Data_Wrap_Struct( klass, my_structure_gc_mark, my_structure_destroy, mine );
Ruby然后在必要时负责调用它。
最后,要获取扩展保存的Ruby数据,您只需打开结构并像struct
的任何其他部分一样引用它。举例来说,以下是如何实现上述的访问器方法:
VALUE my_ext_get_some_ruby_val( VALUE self ) {
MyStructure *mine;
Data_Get_Struct( self, MyStructure, mine );
return mine->some_ruby_val;
}